Skip to content

Commit 3400192

Browse files
authored
Merge pull request #1663 from YouUWd/master
fix queryCusor() fails in streaming mode of MySQL Connector/J (fetchSize=Integer.MIN_VALUE) #1654 This is a workaround for https://bugs.mysql.com/bug.php?id=96786
2 parents 50751a3 + 25ddbb9 commit 3400192

File tree

6 files changed

+157
-5
lines changed

6 files changed

+157
-5
lines changed

pom.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,12 @@
252252
<version>42.2.5</version>
253253
<scope>test</scope>
254254
</dependency>
255+
<dependency>
256+
<groupId>mysql</groupId>
257+
<artifactId>mysql-connector-java</artifactId>
258+
<version>8.0.17</version>
259+
<scope>test</scope>
260+
</dependency>
255261
<dependency>
256262
<groupId>org.assertj</groupId>
257263
<artifactId>assertj-core</artifactId>
@@ -267,13 +273,19 @@
267273
<dependency>
268274
<groupId>org.testcontainers</groupId>
269275
<artifactId>junit-jupiter</artifactId>
270-
<version>1.11.2</version>
276+
<version>1.12.1</version>
271277
<scope>test</scope>
272278
</dependency>
273279
<dependency>
274280
<groupId>org.testcontainers</groupId>
275281
<artifactId>postgresql</artifactId>
276-
<version>1.11.2</version>
282+
<version>1.12.1</version>
283+
<scope>test</scope>
284+
</dependency>
285+
<dependency>
286+
<groupId>org.testcontainers</groupId>
287+
<artifactId>mysql</artifactId>
288+
<version>1.12.1</version>
277289
<scope>test</scope>
278290
</dependency>
279291
</dependencies>

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowB
102102
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
103103
Connection connection = getConnection(ms.getStatementLog());
104104
Statement stmt = handler.prepare(connection, transaction.getTimeout());
105-
stmt.closeOnCompletion();
106105
handler.parameterize(stmt);
107-
return handler.queryCursor(stmt);
106+
Cursor<E> cursor = handler.queryCursor(stmt);
107+
stmt.closeOnCompletion();
108+
return cursor;
108109
}
109110

110111
@Override

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ protected <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowB
7171
Configuration configuration = ms.getConfiguration();
7272
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, null, boundSql);
7373
Statement stmt = prepareStatement(handler, ms.getStatementLog());
74+
Cursor<E> cursor = handler.queryCursor(stmt);
7475
stmt.closeOnCompletion();
75-
return handler.queryCursor(stmt);
76+
return cursor;
7677
}
7778

7879
@Override

src/test/java/org/apache/ibatis/submitted/cursor_simple/Mapper.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.apache.ibatis.submitted.cursor_simple;
1717

18+
import org.apache.ibatis.annotations.Options;
1819
import org.apache.ibatis.annotations.Select;
1920
import org.apache.ibatis.cursor.Cursor;
2021
import org.apache.ibatis.session.RowBounds;
@@ -33,4 +34,8 @@ public interface Mapper {
3334
"select null id, null name from (values (0))"
3435
})
3536
Cursor<User> getNullUsers(RowBounds rowBounds);
37+
38+
@Select("select * from users")
39+
@Options(fetchSize = Integer.MIN_VALUE)
40+
Cursor<User> getUsersMysqlStream();
3641
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright 2009-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.apache.ibatis.submitted.cursor_simple;
17+
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
20+
import java.io.IOException;
21+
import java.util.Iterator;
22+
23+
import org.apache.ibatis.BaseDataTest;
24+
import org.apache.ibatis.cursor.Cursor;
25+
import org.apache.ibatis.mapping.Environment;
26+
import org.apache.ibatis.session.Configuration;
27+
import org.apache.ibatis.session.ExecutorType;
28+
import org.apache.ibatis.session.SqlSession;
29+
import org.apache.ibatis.session.SqlSessionFactory;
30+
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
31+
import org.apache.ibatis.testcontainers.MysqlContainer;
32+
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
33+
import org.junit.jupiter.api.BeforeAll;
34+
import org.junit.jupiter.api.Tag;
35+
import org.junit.jupiter.api.Test;
36+
37+
@Tag("TestcontainersTests")
38+
class MysqlCursorTest {
39+
40+
private static SqlSessionFactory sqlSessionFactory;
41+
42+
@BeforeAll
43+
static void setUp() throws Exception {
44+
Configuration configuration = new Configuration();
45+
Environment environment = new Environment("development", new JdbcTransactionFactory(),
46+
MysqlContainer.getUnpooledDataSource());
47+
configuration.setEnvironment(environment);
48+
configuration.addMapper(Mapper.class);
49+
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
50+
51+
BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
52+
"org/apache/ibatis/submitted/cursor_simple/CreateDB.sql");
53+
}
54+
55+
@Test
56+
void testMySqlStreamResultSet() throws IOException {
57+
// #1654 and https://bugs.mysql.com/bug.php?id=96786
58+
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
59+
Mapper mapper = sqlSession.getMapper(Mapper.class);
60+
{
61+
Cursor<User> cursor = mapper.getUsersMysqlStream();
62+
Iterator<User> iterator = cursor.iterator();
63+
User user = iterator.next();
64+
assertEquals("User1", user.getName());
65+
cursor.close();
66+
}
67+
}
68+
}
69+
70+
@Test
71+
void testMySqlStreamResultSetBatch() throws IOException {
72+
// #1654 and https://bugs.mysql.com/bug.php?id=96786
73+
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
74+
Mapper mapper = sqlSession.getMapper(Mapper.class);
75+
{
76+
Cursor<User> cursor = mapper.getUsersMysqlStream();
77+
Iterator<User> iterator = cursor.iterator();
78+
User user = iterator.next();
79+
assertEquals("User1", user.getName());
80+
cursor.close();
81+
}
82+
}
83+
}
84+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2009-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.apache.ibatis.testcontainers;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
22+
import org.testcontainers.containers.MySQLContainer;
23+
24+
public class MysqlContainer {
25+
26+
private static final String DB_NAME = "mybatis_test";
27+
private static final String USERNAME = "u";
28+
private static final String PASSWORD = "p";
29+
private static final String DRIVER = "com.mysql.cj.jdbc.Driver";
30+
31+
private static final MySQLContainer<?> INSTANCE = initContainer();
32+
33+
private static MySQLContainer<?> initContainer() {
34+
@SuppressWarnings("resource")
35+
MySQLContainer<?> container = new MySQLContainer<>().withDatabaseName(DB_NAME).withUsername(USERNAME)
36+
.withPassword(PASSWORD);
37+
container.start();
38+
return container;
39+
}
40+
41+
public static DataSource getUnpooledDataSource() {
42+
return new UnpooledDataSource(MysqlContainer.DRIVER, INSTANCE.getJdbcUrl(), MysqlContainer.USERNAME,
43+
MysqlContainer.PASSWORD);
44+
}
45+
46+
private MysqlContainer() {
47+
super();
48+
}
49+
}

0 commit comments

Comments
 (0)