Skip to content

Commit 534fda2

Browse files
BaseExecutor's deferredLoads property type was replaced by ConcurrentLinkedQueue to prevent unwanted ConcurrentModificationException.
1 parent 42bdfd1 commit 534fda2

File tree

13 files changed

+311
-2
lines changed

13 files changed

+311
-2
lines changed

src/main/java/org/apache/ibatis/executor/BaseExecutor.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
import java.sql.SQLException;
1717
import java.sql.Statement;
1818
import java.util.*;
19+
import java.util.concurrent.ConcurrentLinkedQueue;
1920

2021
public abstract class BaseExecutor implements Executor {
2122

2223
protected Transaction transaction;
2324

24-
protected List<DeferredLoad> deferredLoads;
25+
protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
2526
protected PerpetualCache localCache;
2627
protected Configuration configuration;
2728

@@ -32,7 +33,7 @@ public abstract class BaseExecutor implements Executor {
3233

3334
protected BaseExecutor(Configuration configuration, Transaction transaction) {
3435
this.transaction = transaction;
35-
this.deferredLoads = new ArrayList<DeferredLoad>();
36+
this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>();
3637
this.localCache = new PerpetualCache("LocalCache");
3738
this.closed = false;
3839
this.configuration = configuration;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.apache.ibatis.submitted.lazyload_common_property;
2+
3+
public class Child {
4+
private Integer id;
5+
private String name;
6+
private Father father;
7+
private GrandFather grandFather;
8+
public Integer getId() {
9+
return id;
10+
}
11+
public void setId(Integer id) {
12+
this.id = id;
13+
}
14+
public String getName() {
15+
return name;
16+
}
17+
public void setName(String name) {
18+
this.name = name;
19+
}
20+
public Father getFather() {
21+
return father;
22+
}
23+
public void setFather(Father father) {
24+
this.father = father;
25+
}
26+
public GrandFather getGrandFather() {
27+
return grandFather;
28+
}
29+
public void setGrandFather(GrandFather grandFather) {
30+
this.grandFather = grandFather;
31+
}
32+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.apache.ibatis.submitted.lazyload_common_property;
2+
3+
public interface ChildMapper {
4+
public Child selectById(Integer id);
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<!DOCTYPE mapper
3+
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4+
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5+
6+
<mapper namespace="org.apache.ibatis.submitted.lazyload_common_property.ChildMapper">
7+
8+
<resultMap id="ChildMap" type="Child">
9+
<id property="id" column="id"/>
10+
<result property="name" column="name"/>
11+
<association property="father" column="father_id" select="org.apache.ibatis.submitted.lazyload_common_property.FatherMapper.selectById"/>
12+
<association property="grandFather" column="grand_father_id" select="org.apache.ibatis.submitted.lazyload_common_property.GrandFatherMapper.selectById"/>
13+
</resultMap>
14+
15+
16+
<select id="selectById" resultMap="ChildMap" parameterType="int">
17+
SELECT id, name, father_id, grand_father_id
18+
FROM Child
19+
WHERE id = #{id}
20+
</select>
21+
</mapper>
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package org.apache.ibatis.submitted.lazyload_common_property;
2+
3+
import java.io.PrintWriter;
4+
import java.io.Reader;
5+
import java.sql.Connection;
6+
import java.sql.DriverManager;
7+
8+
import org.apache.ibatis.io.Resources;
9+
import org.apache.ibatis.jdbc.ScriptRunner;
10+
import org.apache.ibatis.session.SqlSession;
11+
import org.apache.ibatis.session.SqlSessionFactory;
12+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
13+
import org.junit.BeforeClass;
14+
import org.junit.Test;
15+
16+
public class CommonPropertyLazyLoadError {
17+
18+
private static SqlSessionFactory sqlSessionFactory;
19+
20+
@BeforeClass
21+
public static void initDatabase() throws Exception {
22+
Connection conn = null;
23+
24+
try {
25+
Class.forName("org.hsqldb.jdbcDriver");
26+
conn = DriverManager.getConnection("jdbc:hsqldb:mem:lazyload_common_property", "sa",
27+
"");
28+
29+
Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/lazyload_common_property/CreateDB.sql");
30+
31+
ScriptRunner runner = new ScriptRunner(conn);
32+
runner.setLogWriter(null);
33+
runner.setErrorLogWriter(new PrintWriter(System.err));
34+
runner.runScript(reader);
35+
conn.commit();
36+
reader.close();
37+
38+
reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/lazyload_common_property/ibatisConfig.xml");
39+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
40+
reader.close();
41+
} finally {
42+
if (conn != null) {
43+
conn.close();
44+
}
45+
}
46+
}
47+
48+
@Test
49+
public void testLazyLoadWithNoAncestor() {
50+
SqlSession sqlSession = sqlSessionFactory.openSession();
51+
try {
52+
ChildMapper childMapper = sqlSession.getMapper(ChildMapper.class);
53+
54+
childMapper.selectById(1);
55+
} finally {
56+
sqlSession.close();
57+
}
58+
}
59+
@Test
60+
public void testLazyLoadWithFirstAncestor() {
61+
SqlSession sqlSession = sqlSessionFactory.openSession();
62+
try {
63+
FatherMapper fatherMapper = sqlSession.getMapper(FatherMapper.class);
64+
ChildMapper childMapper = sqlSession.getMapper(ChildMapper.class);
65+
66+
fatherMapper.selectById(1);
67+
childMapper.selectById(1);
68+
} finally {
69+
sqlSession.close();
70+
}
71+
}
72+
@Test
73+
public void testLazyLoadWithAllAncestors() {
74+
SqlSession sqlSession = sqlSessionFactory.openSession();
75+
try {
76+
GrandFatherMapper grandFatherMapper = sqlSession.getMapper(GrandFatherMapper.class);
77+
FatherMapper fatherMapper = sqlSession.getMapper(FatherMapper.class);
78+
ChildMapper childMapper = sqlSession.getMapper(ChildMapper.class);
79+
80+
grandFatherMapper.selectById(1);
81+
fatherMapper.selectById(1);
82+
childMapper.selectById(1);
83+
} finally {
84+
sqlSession.close();
85+
}
86+
}
87+
@Test
88+
public void testLazyLoadSkipFirstAncestor() {
89+
SqlSession sqlSession = sqlSessionFactory.openSession();
90+
try {
91+
GrandFatherMapper grandFatherMapper = sqlSession.getMapper(GrandFatherMapper.class);
92+
ChildMapper childMapper = sqlSession.getMapper(ChildMapper.class);
93+
94+
grandFatherMapper.selectById(1);
95+
childMapper.selectById(1);
96+
} finally {
97+
sqlSession.close();
98+
}
99+
}
100+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
create table Child (
2+
id int,
3+
name varchar(100),
4+
father_id int,
5+
grand_father_id int
6+
);
7+
create table Father (
8+
id int,
9+
name varchar(100),
10+
grand_father_id int
11+
);
12+
create table GrandFather (
13+
id int,
14+
name varchar(100)
15+
);
16+
17+
INSERT INTO Child (id, name, father_id, grand_father_id)
18+
VALUES (1, 'John Smith jr', 1, 1);
19+
20+
INSERT INTO Father (id, name, grand_father_id)
21+
VALUES (1, 'John Smith', 1);
22+
23+
INSERT INTO GrandFather (id, name)
24+
VALUES (1, 'John Smith sen');
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.apache.ibatis.submitted.lazyload_common_property;
2+
3+
public class Father {
4+
private Integer id;
5+
private String name;
6+
private GrandFather grandFather;
7+
public Integer getId() {
8+
return id;
9+
}
10+
public void setId(Integer id) {
11+
this.id = id;
12+
}
13+
public String getName() {
14+
return name;
15+
}
16+
public void setName(String name) {
17+
this.name = name;
18+
}
19+
public GrandFather getGrandFather() {
20+
return grandFather;
21+
}
22+
public void setGrandFather(GrandFather grandFather) {
23+
this.grandFather = grandFather;
24+
}
25+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.apache.ibatis.submitted.lazyload_common_property;
2+
3+
public interface FatherMapper {
4+
public Father selectById(Integer id);
5+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<!DOCTYPE mapper
3+
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
4+
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
5+
6+
<mapper namespace="org.apache.ibatis.submitted.lazyload_common_property.FatherMapper">
7+
8+
<resultMap id="FatherMap" type="Father">
9+
<id property="id" column="id"/>
10+
<result property="name" column="name"/>
11+
<association property="grandFather" column="grand_father_id" select="org.apache.ibatis.submitted.lazyload_common_property.GrandFatherMapper.selectById"/>
12+
</resultMap>
13+
14+
15+
<select id="selectById" resultMap="FatherMap" parameterType="int">
16+
SELECT id, name, grand_father_id
17+
FROM Father
18+
WHERE id = #{id}
19+
</select>
20+
</mapper>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.apache.ibatis.submitted.lazyload_common_property;
2+
3+
public class GrandFather {
4+
private Integer id;
5+
private String name;
6+
public Integer getId() {
7+
return id;
8+
}
9+
public void setId(Integer id) {
10+
this.id = id;
11+
}
12+
public String getName() {
13+
return name;
14+
}
15+
public void setName(String name) {
16+
this.name = name;
17+
}
18+
}

0 commit comments

Comments
 (0)