Skip to content

Commit 744e79e

Browse files
committed
fixed output parameter caching issue, and created NullCacheKey instance which is a little safer (avoids accidental usage of the NULL_CACHE_KEY field)
1 parent b07d57f commit 744e79e

File tree

4 files changed

+66
-18
lines changed

4 files changed

+66
-18
lines changed

src/main/java/org/apache/ibatis/cache/CacheKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
public class CacheKey {
77

8-
public static final CacheKey NULL_CACHE_KEY = new CacheKey();
8+
public static final CacheKey NULL_CACHE_KEY = new NullCacheKey();
99

1010
private static final int DEFAULT_MULTIPLYER = 37;
1111
private static final int DEFAULT_HASHCODE = 17;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.apache.ibatis.cache;
2+
3+
4+
public final class NullCacheKey extends CacheKey {
5+
6+
public NullCacheKey() {
7+
super();
8+
}
9+
10+
@Override
11+
public void update(Object object) {
12+
throw new CacheException("Not allowed to update a NullCacheKey instance.");
13+
}
14+
15+
@Override
16+
public void updateAll(Object[] objects) {
17+
throw new CacheException("Not allowed to update a NullCacheKey instance.");
18+
}
19+
}

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

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
import org.apache.ibatis.cache.CacheKey;
44
import org.apache.ibatis.cache.impl.PerpetualCache;
55
import static org.apache.ibatis.executor.ExecutionPlaceholder.EXECUTION_PLACEHOLDER;
6-
import org.apache.ibatis.mapping.BoundSql;
7-
import org.apache.ibatis.mapping.MappedStatement;
8-
import org.apache.ibatis.mapping.ParameterMapping;
6+
7+
import org.apache.ibatis.mapping.*;
98
import org.apache.ibatis.reflection.MetaObject;
109
import org.apache.ibatis.session.ResultHandler;
1110
import org.apache.ibatis.session.RowBounds;
@@ -24,6 +23,7 @@ public abstract class BaseExecutor implements Executor {
2423

2524
protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
2625
protected PerpetualCache localCache;
26+
protected PerpetualCache localOutputParameterCache;
2727
protected Configuration configuration;
2828

2929
protected int queryStack = 0;
@@ -35,6 +35,7 @@ protected BaseExecutor(Configuration configuration, Transaction transaction) {
3535
this.transaction = transaction;
3636
this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>();
3737
this.localCache = new PerpetualCache("LocalCache");
38+
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
3839
this.closed = false;
3940
this.configuration = configuration;
4041
}
@@ -57,6 +58,7 @@ public void close(boolean forceRollback) {
5758
transaction = null;
5859
deferredLoads = null;
5960
localCache = null;
61+
localOutputParameterCache = null;
6062
batchResults = null;
6163
closed = true;
6264
}
@@ -86,17 +88,11 @@ public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, Res
8688
try {
8789
queryStack++;
8890
CacheKey key = createCacheKey(ms, parameter, rowBounds);
89-
final List cachedList = (List) localCache.getObject(key);
90-
if (cachedList != null) {
91-
list = cachedList;
91+
list = (List) localCache.getObject(key);
92+
if (list != null) {
93+
handleLocallyCachedOutputParameters(ms, key, parameter);
9294
} else {
93-
localCache.putObject(key, EXECUTION_PLACEHOLDER);
94-
try {
95-
list = doQuery(ms, parameter, rowBounds, resultHandler);
96-
} finally {
97-
localCache.removeObject(key);
98-
}
99-
localCache.putObject(key, list);
95+
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key);
10096
}
10197
} finally {
10298
queryStack--;
@@ -173,6 +169,7 @@ public void rollback(boolean required) throws SQLException {
173169
public void clearLocalCache() {
174170
if (!closed) {
175171
localCache.clear();
172+
localOutputParameterCache.clear();
176173
}
177174
}
178175

@@ -195,6 +192,38 @@ protected void closeStatement(Statement statement) {
195192
}
196193
}
197194

195+
private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter) {
196+
if (ms.getStatementType() == StatementType.CALLABLE) {
197+
final Object cachedParameter = localOutputParameterCache.getObject(key);
198+
if (cachedParameter != null && parameter != null) {
199+
final MetaObject metaCachedParameter = MetaObject.forObject(cachedParameter);
200+
final MetaObject metaParameter = MetaObject.forObject(parameter);
201+
for (ParameterMapping parameterMapping : ms.getBoundSql(parameter).getParameterMappings()) {
202+
if (parameterMapping.getMode() != ParameterMode.IN) {
203+
final String parameterName = parameterMapping.getProperty();
204+
final Object cachedValue = metaCachedParameter.getValue(parameterName);
205+
metaParameter.setValue(parameterName, cachedValue);
206+
}
207+
}
208+
}
209+
}
210+
}
211+
212+
private List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key) throws SQLException {
213+
List list;
214+
localCache.putObject(key, EXECUTION_PLACEHOLDER);
215+
try {
216+
list = doQuery(ms, parameter, rowBounds, resultHandler);
217+
} finally {
218+
localCache.removeObject(key);
219+
}
220+
localCache.putObject(key, list);
221+
if (ms.getStatementType() == StatementType.CALLABLE) {
222+
localOutputParameterCache.putObject(key, parameter);
223+
}
224+
return list;
225+
}
226+
198227
private class DeferredLoad {
199228

200229
MappedStatement mappedStatement;

src/test/java/org/apache/ibatis/submitted/sptests/SPTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ public void testAdderAsSelectDoubleCall1() {
9898
spMapper.adder(parameter);
9999
assertEquals((Integer) 5, parameter.getSum());
100100

101-
// clear cache is required in this instance.
102-
sqlSession.clearCache();
101+
// Resolved Output Parameter Caching Issue for Callable statements
102+
// sqlSession.clearCache();
103103

104104
parameter = new Parameter();
105105
parameter.setAddend1(2);
@@ -276,8 +276,8 @@ public void testCallWithResultSet4() {
276276
assertEquals(2, parms.get("totalRows"));
277277
assertEquals(2, names.size());
278278

279-
// clear cache is required in this instance.
280-
sqlSession.clearCache();
279+
// Resolved Output Parameter Caching Issue for Callable statements
280+
// sqlSession.clearCache();
281281

282282
parms = new HashMap<String, Object>();
283283
parms.put("lowestId", 2);

0 commit comments

Comments
 (0)