Skip to content

Commit 43500e9

Browse files
committed
Fixes mybatis#146. Avoid using caches that are dirty but use the rest.
1 parent 0da9358 commit 43500e9

File tree

7 files changed

+51
-54
lines changed

7 files changed

+51
-54
lines changed

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

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ public void clear(Cache cache) {
2828
getTransactionalCache(cache).clear();
2929
}
3030

31+
public Object getObject(Cache cache, CacheKey key) {
32+
return getTransactionalCache(cache).getObject(key);
33+
}
34+
3135
public void putObject(Cache cache, CacheKey key, Object value) {
3236
getTransactionalCache(cache).putObject(key, value);
3337
}

src/main/java/org/apache/ibatis/cache/decorators/TransactionalCache.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2012 the original author or authors.
2+
* Copyright 2009-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,7 +44,13 @@ public int getSize() {
4444
}
4545

4646
public Object getObject(Object key) {
47-
return delegate.getObject(key);
47+
if (clearOnCommit) return null;
48+
delegate.getReadWriteLock().readLock().lock();
49+
try {
50+
return delegate.getObject(key);
51+
} finally {
52+
delegate.getReadWriteLock().readLock().unlock();
53+
}
4854
}
4955

5056
public ReadWriteLock getReadWriteLock() {

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

+14-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2012 the original author or authors.
2+
* Copyright 2009-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,18 +34,10 @@
3434
public class CachingExecutor implements Executor {
3535

3636
private Executor delegate;
37-
private boolean autoCommit; // issue #573. No need to call commit() on autoCommit sessions
3837
private TransactionalCacheManager tcm = new TransactionalCacheManager();
3938

40-
private boolean dirty;
41-
4239
public CachingExecutor(Executor delegate) {
43-
this(delegate, false);
44-
}
45-
46-
public CachingExecutor(Executor delegate, boolean autoCommit) {
4740
this.delegate = delegate;
48-
this.autoCommit = autoCommit;
4941
}
5042

5143
public Transaction getTransaction() {
@@ -54,9 +46,8 @@ public Transaction getTransaction() {
5446

5547
public void close(boolean forceRollback) {
5648
try {
57-
//issue #499. Unresolved session handling
58-
//issue #573. Autocommit sessions should commit
59-
if (dirty && !autoCommit) {
49+
//issues #499, #524 and #573
50+
if (forceRollback) {
6051
tcm.rollback();
6152
} else {
6253
tcm.commit();
@@ -81,28 +72,23 @@ public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds r
8172
return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
8273
}
8374

84-
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
75+
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
76+
throws SQLException {
8577
Cache cache = ms.getCache();
8678
if (cache != null) {
8779
flushCacheIfRequired(ms);
88-
if (ms.isUseCache() && resultHandler == null) {
80+
if (ms.isUseCache() && resultHandler == null) {
8981
ensureNoOutParams(ms, parameterObject, boundSql);
90-
if (!dirty) {
91-
cache.getReadWriteLock().readLock().lock();
92-
try {
93-
@SuppressWarnings("unchecked")
94-
List<E> cachedList = (List<E>) cache.getObject(key);
95-
if (cachedList != null) return cachedList;
96-
} finally {
97-
cache.getReadWriteLock().readLock().unlock();
98-
}
82+
@SuppressWarnings("unchecked")
83+
List<E> list = (List<E>) cache.getObject(key);
84+
if (list == null) {
85+
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
86+
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
87+
return list;
9988
}
100-
List<E> list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
101-
tcm.putObject(cache, key, list); // issue #578. Query must be not synchronized to prevent deadlocks
102-
return list;
10389
}
10490
}
105-
return delegate.<E>query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
91+
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
10692
}
10793

10894
public List<BatchResult> flushStatements() throws SQLException {
@@ -112,13 +98,11 @@ public List<BatchResult> flushStatements() throws SQLException {
11298
public void commit(boolean required) throws SQLException {
11399
delegate.commit(required);
114100
tcm.commit();
115-
dirty = false;
116101
}
117102

118103
public void rollback(boolean required) throws SQLException {
119104
try {
120105
delegate.rollback(required);
121-
dirty = false;
122106
} finally {
123107
if (required) {
124108
tcm.rollback();
@@ -154,8 +138,7 @@ public void clearLocalCache() {
154138

155139
private void flushCacheIfRequired(MappedStatement ms) {
156140
Cache cache = ms.getCache();
157-
if (cache != null && ms.isFlushCacheRequired()) {
158-
dirty = true; // issue #524. Disable using cached data for this session
141+
if (cache != null && ms.isFlushCacheRequired()) {
159142
tcm.clear(cache);
160143
}
161144
}

src/main/java/org/apache/ibatis/session/Configuration.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2013 the original author or authors.
2+
* Copyright 2009-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -471,10 +471,6 @@ public Executor newExecutor(Transaction transaction) {
471471
}
472472

473473
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
474-
return newExecutor(transaction, executorType, false);
475-
}
476-
477-
public Executor newExecutor(Transaction transaction, ExecutorType executorType, boolean autoCommit) {
478474
executorType = executorType == null ? defaultExecutorType : executorType;
479475
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
480476
Executor executor;
@@ -486,7 +482,7 @@ public Executor newExecutor(Transaction transaction, ExecutorType executorType,
486482
executor = new SimpleExecutor(this, transaction);
487483
}
488484
if (cacheEnabled) {
489-
executor = new CachingExecutor(executor, autoCommit);
485+
executor = new CachingExecutor(executor);
490486
}
491487
executor = (Executor) interceptorChain.pluginAll(executor);
492488
return executor;

src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSession.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2012 the original author or authors.
2+
* Copyright 2009-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,17 +40,18 @@ public class DefaultSqlSession implements SqlSession {
4040
private Configuration configuration;
4141
private Executor executor;
4242

43+
private boolean autoCommit;
4344
private boolean dirty;
44-
45-
@Deprecated
45+
4646
public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
47-
this(configuration, executor);
48-
}
49-
50-
public DefaultSqlSession(Configuration configuration, Executor executor) {
5147
this.configuration = configuration;
5248
this.executor = executor;
5349
this.dirty = false;
50+
this.autoCommit = autoCommit;
51+
}
52+
53+
public DefaultSqlSession(Configuration configuration, Executor executor) {
54+
this(configuration, executor, false);
5455
}
5556

5657
public <T> T selectOne(String statement) {
@@ -231,7 +232,7 @@ public void clearCache() {
231232
}
232233

233234
private boolean isCommitOrRollbackRequired(boolean force) {
234-
return dirty || force;
235+
return (!autoCommit && dirty) || force;
235236
}
236237

237238
private Object wrapCollection(final Object object) {

src/main/java/org/apache/ibatis/session/defaults/DefaultSqlSessionFactory.java

+12-4
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionI
8181
final Environment environment = configuration.getEnvironment();
8282
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
8383
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
84-
final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
85-
return new DefaultSqlSession(configuration, executor);
84+
final Executor executor = configuration.newExecutor(tx, execType);
85+
return new DefaultSqlSession(configuration, executor, autoCommit);
8686
} catch (Exception e) {
8787
closeTransaction(tx); // may have fetched a connection so lets call close()
8888
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
@@ -93,11 +93,19 @@ private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionI
9393

9494
private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
9595
try {
96+
boolean autoCommit;
97+
try {
98+
autoCommit = connection.getAutoCommit();
99+
} catch (SQLException e) {
100+
// Failover to true, as most poor drivers
101+
// or databases won't support transactions
102+
autoCommit = true;
103+
}
96104
final Environment environment = configuration.getEnvironment();
97105
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
98106
final Transaction tx = transactionFactory.newTransaction(connection);
99-
final Executor executor = configuration.newExecutor(tx, execType, connection.getAutoCommit());
100-
return new DefaultSqlSession(configuration, executor);
107+
final Executor executor = configuration.newExecutor(tx, execType);
108+
return new DefaultSqlSession(configuration, executor, autoCommit);
101109
} catch (Exception e) {
102110
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
103111
} finally {

src/test/java/org/apache/ibatis/submitted/cache/CacheTest.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2012 the original author or authors.
2+
* Copyright 2009-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,13 +18,12 @@
1818
import java.io.Reader;
1919
import java.sql.Connection;
2020

21-
import junit.framework.Assert;
22-
2321
import org.apache.ibatis.io.Resources;
2422
import org.apache.ibatis.jdbc.ScriptRunner;
2523
import org.apache.ibatis.session.SqlSession;
2624
import org.apache.ibatis.session.SqlSessionFactory;
2725
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
26+
import org.junit.Assert;
2827
import org.junit.Before;
2928
import org.junit.Test;
3029

0 commit comments

Comments
 (0)