1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.submitted.cursor_cache_oom;
17
18 import java.io.IOException;
19 import java.io.Reader;
20 import java.lang.reflect.Field;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.apache.ibatis.BaseDataTest;
25 import org.apache.ibatis.cache.CacheKey;
26 import org.apache.ibatis.cursor.Cursor;
27 import org.apache.ibatis.cursor.defaults.DefaultCursor;
28 import org.apache.ibatis.executor.resultset.DefaultResultSetHandler;
29 import org.apache.ibatis.io.Resources;
30 import org.apache.ibatis.session.SqlSession;
31 import org.apache.ibatis.session.SqlSessionFactory;
32 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
33 import org.apache.ibatis.session.defaults.DefaultSqlSession;
34 import org.junit.jupiter.api.Assertions;
35 import org.junit.jupiter.api.BeforeAll;
36 import org.junit.jupiter.api.Test;
37
38 @SuppressWarnings("ALL")
39 class CursorOomTest {
40
41 private static SqlSessionFactory sqlSessionFactory;
42
43 @BeforeAll
44 static void setUp() throws Exception {
45
46 try (Reader reader = Resources
47 .getResourceAsReader("org/apache/ibatis/submitted/cursor_cache_oom/mybatis-config.xml")) {
48 sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
49 }
50
51
52 BaseDataTest.runScript(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(),
53 "org/apache/ibatis/submitted/cursor_cache_oom/CreateDB.sql");
54 }
55
56 private static Map<CacheKey, Object> getNestedResultObjects(Cursor<User> users)
57 throws IllegalAccessException, NoSuchFieldException {
58 DefaultCursor<User> defaultCursor = (DefaultCursor<User>) users;
59 Field resultSetHandlerField = DefaultCursor.class.getDeclaredField("resultSetHandler");
60 resultSetHandlerField.setAccessible(true);
61 DefaultResultSetHandler defaultResultSetHandler = (DefaultResultSetHandler) resultSetHandlerField
62 .get(defaultCursor);
63 Field nestedResultObjectsField = DefaultResultSetHandler.class.getDeclaredField("nestedResultObjects");
64 nestedResultObjectsField.setAccessible(true);
65 return (Map<CacheKey, Object>) nestedResultObjectsField.get(defaultResultSetHandler);
66 }
67
68 private static List<Cursor<?>> getCursors(SqlSession sqlSession) throws NoSuchFieldException, IllegalAccessException {
69 DefaultSqlSession session = (DefaultSqlSession) sqlSession;
70 Field cursorListField = DefaultSqlSession.class.getDeclaredField("cursorList");
71 cursorListField.setAccessible(true);
72 return (List<Cursor<?>>) cursorListField.get(session);
73 }
74
75 @Test
76 void shouldNotCacheAllDataForWholeSessionWhileUsingCursor()
77 throws IOException, NoSuchFieldException, IllegalAccessException {
78 try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
79 Mapper mapper = sqlSession.getMapper(Mapper.class);
80 try (Cursor<User> users = mapper.fetchUsers()) {
81 for (User user : users) {
82 consumeUser(user);
83 }
84 Map nestedResultObjects = getNestedResultObjects(users);
85
86 Assertions.assertFalse(nestedResultObjects.isEmpty());
87
88
89
90
91 }
92
93 List<Cursor<?>> cursorList = getCursors(sqlSession);
94
95
96
97
98 Assertions
99 .assertTrue(cursorList.isEmpty() || getNestedResultObjects((Cursor<User>) cursorList.get(0)).size() <= 2);
100 }
101 }
102
103 private void consumeUser(User user) {
104
105 }
106 }