33import org .apache .ibatis .cache .CacheKey ;
44import org .apache .ibatis .cache .impl .PerpetualCache ;
55import 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 .*;
98import org .apache .ibatis .reflection .MetaObject ;
109import org .apache .ibatis .session .ResultHandler ;
1110import 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 ;
0 commit comments