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 List<Cursor<?>> cursorList = (List<Cursor<?>>) cursorListField.get(session);
73 return cursorList;
74 }
75
76 @Test
77 void shouldNotCacheAllDataForWholeSessionWhileUsingCursor()
78 throws IOException, NoSuchFieldException, IllegalAccessException {
79 try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
80 Mapper mapper = sqlSession.getMapper(Mapper.class);
81 try (Cursor<User> users = mapper.fetchUsers()) {
82 for (User user : users) {
83 consumeUser(user);
84 }
85 Map nestedResultObjects = getNestedResultObjects(users);
86
87 Assertions.assertFalse(nestedResultObjects.isEmpty());
88
89
90
91
92 }
93
94 List<Cursor<?>> cursorList = getCursors(sqlSession);
95
96
97
98
99 Assertions
100 .assertTrue(cursorList.isEmpty() || getNestedResultObjects((Cursor<User>) cursorList.get(0)).size() <= 2);
101 }
102 }
103
104 private void consumeUser(User user) {
105
106 }
107 }