diff --git a/pom.xml b/pom.xml
index 883dd87ce3..3f8fd9aee7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -238,10 +238,25 @@
org.springframework
spring
- 2.0
+ 2.5.6
provided
-
+
+
+ org.apache.ibatis
+ ibatis-sqlmap
+ 2.3.4.726
+ test
+
+
+
log4j
log4j
@@ -348,12 +363,6 @@
0.7.1-rc2
test
-
- com.jolbox
- bonecp-test-commons
- 0.7.1-rc2
- test
-
proxool
diff --git a/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java b/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java
index 092c360101..1562177d21 100644
--- a/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java
+++ b/src/main/java/com/alibaba/druid/filter/logging/LogFilter.java
@@ -301,6 +301,14 @@ public abstract class LogFilter extends FilterEventAdapter implements LogFilterM
connectionLog("connect commited. id " + connection.getId());
}
}
+
+ @Override
+ public void connection_setAutoCommit(FilterChain chain, ConnectionProxy connection, boolean autoCommit)
+ throws SQLException {
+
+ connectionLog("connect setAutoComment " + autoCommit + ". id " + connection.getId());
+ chain.connection_setAutoCommit(connection, autoCommit);
+ }
@Override
public void connection_close(FilterChain chain, ConnectionProxy connection) throws SQLException {
diff --git a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java
index ab67d4a2ef..00415264e6 100644
--- a/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java
+++ b/src/main/java/com/alibaba/druid/filter/stat/StatFilter.java
@@ -488,9 +488,10 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
String sql = resultSet.getSql();
if (sql != null) {
- JdbcSqlStat sqlStat = getSqlStat(sql);
+ JdbcSqlStat sqlStat = resultSet.getSqlStat();
if (sqlStat != null) {
sqlStat.addFetchRowCount(fetchCount);
+ sqlStat.addResultSetHoldTimeNano(nanoSpan);
}
}
diff --git a/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxy.java b/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxy.java
index 0577ef2cdc..a2096f2028 100644
--- a/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxy.java
+++ b/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxy.java
@@ -17,6 +17,8 @@ package com.alibaba.druid.proxy.jdbc;
import java.sql.ResultSet;
+import com.alibaba.druid.stat.JdbcSqlStat;
+
/**
* @author wenshao
*/
@@ -27,6 +29,8 @@ public interface ResultSetProxy extends ResultSet, WrapperProxy {
StatementProxy getStatementProxy();
String getSql();
+
+ JdbcSqlStat getSqlStat();
int getCursorIndex();
diff --git a/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxyImpl.java b/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxyImpl.java
index 1b6b4c959f..39411e481c 100644
--- a/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxyImpl.java
+++ b/src/main/java/com/alibaba/druid/proxy/jdbc/ResultSetProxyImpl.java
@@ -40,6 +40,7 @@ import java.util.Map;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterChainImpl;
+import com.alibaba.druid.stat.JdbcSqlStat;
/**
* @author wenshao
@@ -53,12 +54,14 @@ public class ResultSetProxyImpl extends WrapperProxyImpl implements ResultSetPro
protected int cursorIndex = 0;
protected int fetchRowCount = 0;
protected long constructNano;
+ protected final JdbcSqlStat sqlStat;
public ResultSetProxyImpl(StatementProxy statement, ResultSet resultSet, long id, String sql){
super(resultSet, id);
this.statement = statement;
this.resultSet = resultSet;
this.sql = sql;
+ sqlStat = this.statement.getSqlStat();
}
public long getConstructNano() {
@@ -68,7 +71,7 @@ public class ResultSetProxyImpl extends WrapperProxyImpl implements ResultSetPro
public void setConstructNano(long constructNano) {
this.constructNano = constructNano;
}
-
+
public void setConstructNano() {
if (this.constructNano <= 0) {
this.constructNano = System.nanoTime();
@@ -87,6 +90,10 @@ public class ResultSetProxyImpl extends WrapperProxyImpl implements ResultSetPro
return sql;
}
+ public JdbcSqlStat getSqlStat() {
+ return sqlStat;
+ }
+
public ResultSet getResultSetRaw() {
return resultSet;
}
@@ -1061,7 +1068,7 @@ public class ResultSetProxyImpl extends WrapperProxyImpl implements ResultSetPro
if (iface == ResultSet.class) {
return (T) resultSet;
}
-
+
return super.unwrap(iface);
}
}
diff --git a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java
index 697dcecb21..9c24aa42a9 100644
--- a/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java
+++ b/src/main/java/com/alibaba/druid/stat/DruidDataSourceStatManager.java
@@ -60,7 +60,7 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
if (dataSources.size() == 0) {
try {
-
+
ObjectName objectName = new ObjectName(MBEAN_NAME);
if (!mbeanServer.isRegistered(objectName)) {
mbeanServer.registerMBean(instance, objectName);
@@ -98,9 +98,9 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
public synchronized static void remove(DruidDataSource dataSource) {
ObjectName objectName = dataSources.remove(dataSource);
-
+
if (objectName == null) {
- objectName = dataSource.getObjectName();
+ objectName = dataSource.getObjectName();
}
if (objectName == null) {
@@ -164,54 +164,63 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
Map map = new HashMap();
+ // 0 - 4
map.put("Name", dataSource.getName());
map.put("URL", dataSource.getUrl());
map.put("CreateCount", dataSource.getCreateCount());
map.put("DestroyCount", dataSource.getDestroyCount());
map.put("ConnectCount", dataSource.getConnectCount());
+ // 5 - 9
map.put("CloseCount", dataSource.getCloseCount());
map.put("ActiveCount", dataSource.getActivePeak());
map.put("PoolingCount", dataSource.getPoolingCount());
map.put("LockQueueLength", dataSource.getLockQueueLength());
map.put("WaitThreadCount", dataSource.getNotEmptyWaitThreadPeak());
+ // 10 - 14
map.put("InitialSize", dataSource.getInitialSize());
map.put("MaxActive", dataSource.getMaxActive());
map.put("MinIdle", dataSource.getMinIdle());
map.put("PoolPreparedStatements", dataSource.isPoolPreparedStatements());
map.put("TestOnBorrow", dataSource.isTestOnBorrow());
+ // 15 - 19
map.put("TestOnReturn", dataSource.isTestOnReturn());
map.put("MinEvictableIdleTimeMillis", dataSource.getMinEvictableIdleTimeMillis());
map.put("ConnectErrorCount", dataSource.getConnectErrorCount());
map.put("CreateTimespanMillis", dataSource.getCreateTimespanMillis());
map.put("DbType", dataSource.getDbType());
+ // 20 - 24
map.put("ValidationQuery", dataSource.getValidationQuery());
map.put("ValidationQueryTimeout", dataSource.getValidationQueryTimeout());
map.put("DriverClassName", dataSource.getDriverClassName());
map.put("Username", dataSource.getUsername());
map.put("RemoveAbandonedCount", dataSource.getRemoveAbandonedCount());
+ // 25 - 29
map.put("NotEmptyWaitCount", dataSource.getNotEmptyWaitCount());
map.put("NotEmptyWaitNanos", dataSource.getNotEmptyWaitNanos());
map.put("ErrorCount", dataSource.getErrorCount());
map.put("ReusePreparedStatementCount", dataSource.getCachedPreparedStatementHitCount());
map.put("StartTransactionCount", dataSource.getStartTransactionCount());
+ // 30 - 34
map.put("CommitCount", dataSource.getCommitCount());
map.put("RollbackCount", dataSource.getRollbackCount());
map.put("LastError", JMXUtils.getErrorCompositeData(dataSource.getLastError()));
map.put("LastCreateError", JMXUtils.getErrorCompositeData(dataSource.getLastCreateError()));
map.put("PreparedStatementCacheDeleteCount", dataSource.getCachedPreparedStatementDeleteCount());
-
+
+ // 35 - 39
map.put("PreparedStatementCacheAccessCount", dataSource.getCachedPreparedStatementAccessCount());
map.put("PreparedStatementCacheMissCount", dataSource.getCachedPreparedStatementMissCount());
map.put("PreparedStatementCacheHitCount", dataSource.getCachedPreparedStatementHitCount());
map.put("PreparedStatementCacheCurrentCount", dataSource.getCachedPreparedStatementCount());
map.put("Version", dataSource.getVersion());
+ // 40 -
map.put("LastErrorTime", dataSource.getLastErrorTime());
map.put("LastCreateErrorTime", dataSource.getLastCreateErrorTime());
map.put("CreateErrorCount", dataSource.getCreateErrorCount());
@@ -228,36 +237,130 @@ public class DruidDataSourceStatManager implements DruidDataSourceStatManagerMBe
}
OpenType>[] indexTypes = new OpenType>[] {
- //
- SimpleType.STRING, SimpleType.STRING, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, //
- SimpleType.LONG, SimpleType.INTEGER, SimpleType.INTEGER, SimpleType.INTEGER, SimpleType.INTEGER, //
- SimpleType.INTEGER, SimpleType.INTEGER, SimpleType.INTEGER, SimpleType.BOOLEAN, SimpleType.BOOLEAN, //
- SimpleType.BOOLEAN, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.STRING, //
- SimpleType.STRING, SimpleType.INTEGER, SimpleType.STRING, SimpleType.STRING, SimpleType.LONG, //
- SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG//
- , SimpleType.LONG, SimpleType.LONG, JMXUtils.getThrowableCompositeType(), JMXUtils.getThrowableCompositeType(), SimpleType.LONG //
- , SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.LONG, SimpleType.STRING //
- , SimpleType.DATE , SimpleType.DATE, SimpleType.LONG
+ // 0 - 4
+ SimpleType.STRING, //
+ SimpleType.STRING, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+
+ // 5 - 9
+ SimpleType.LONG, //
+ SimpleType.INTEGER, //
+ SimpleType.INTEGER, //
+ SimpleType.INTEGER, //
+ SimpleType.INTEGER, //
+
+ // 10 - 14
+ SimpleType.INTEGER, //
+ SimpleType.INTEGER, //
+ SimpleType.INTEGER, //
+ SimpleType.BOOLEAN, //
+ SimpleType.BOOLEAN, //
+
+ // 15 - 19
+ SimpleType.BOOLEAN, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.STRING, //
+
+ // 20 - 24
+ SimpleType.STRING, //
+ SimpleType.INTEGER, //
+ SimpleType.STRING, //
+ SimpleType.STRING, //
+ SimpleType.LONG, //
+
+ // 25 - 29
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+
+ // 30 - 34
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ JMXUtils.getThrowableCompositeType(), //
+ JMXUtils.getThrowableCompositeType(), //
+ SimpleType.LONG, //
+
+ // 35 - 39
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.LONG, //
+ SimpleType.STRING, //
+
+ // 40 -
+ SimpleType.DATE, //
+ SimpleType.DATE, //
+ SimpleType.LONG //
//
};
String[] indexNames = {
- //
- "Name", "URL", "CreateCount", "DestroyCount",
+ // 0 - 4
+ "Name", //
+ "URL", //
+ "CreateCount", //
+ "DestroyCount", //
"ConnectCount", //
- "CloseCount", "ActiveCount", "PoolingCount", "LockQueueLength",
+
+ // 5 - 9
+ "CloseCount", //
+ "ActiveCount", //
+ "PoolingCount", //
+ "LockQueueLength", //
"WaitThreadCount", //
- "InitialSize", "MaxActive", "MinIdle", "PoolPreparedStatements",
+
+ // 10 - 14
+ "InitialSize", //
+ "MaxActive", //
+ "MinIdle", //
+ "PoolPreparedStatements", //
"TestOnBorrow", //
- "TestOnReturn", "MinEvictableIdleTimeMillis", "ConnectErrorCount", "CreateTimespanMillis",
+
+ // 15 - 19
+ "TestOnReturn", //
+ "MinEvictableIdleTimeMillis", //
+ "ConnectErrorCount", //
+ "CreateTimespanMillis", //
"DbType", //
- "ValidationQuery", "ValidationQueryTimeout", "DriverClassName", "Username",
+
+ // 20 - 24
+ "ValidationQuery", //
+ "ValidationQueryTimeout", //
+ "DriverClassName", //
+ "Username", //
"RemoveAbandonedCount", //
- "NotEmptyWaitCount", "NotEmptyWaitNanos", "ErrorCount", "ReusePreparedStatementCount",
+
+ // 25 - 29
+ "NotEmptyWaitCount", //
+ "NotEmptyWaitNanos", //
+ "ErrorCount", //
+ "ReusePreparedStatementCount", //
"StartTransactionCount", //
- "CommitCount", "RollbackCount", "LastError", "LastCreateError", "PreparedStatementCacheDeleteCount" //
- , "PreparedStatementCacheAccessCount", "PreparedStatementCacheMissCount", "PreparedStatementCacheHitCount", "PreparedStatementCacheCurrentCount", "Version" //
- , "LastErrorTime", "LastCreateErrorTime", "CreateErrorCount"
+
+ // 30 - 34
+ "CommitCount", //
+ "RollbackCount", //
+ "LastError", //
+ "LastCreateError", //
+ "PreparedStatementCacheDeleteCount", //
+
+ // 35 - 39
+ "PreparedStatementCacheAccessCount", //
+ "PreparedStatementCacheMissCount", //
+ "PreparedStatementCacheHitCount", //
+ "PreparedStatementCacheCurrentCount", //
+ "Version" //
+
+ // 40 -
+ , "LastErrorTime", //
+ "LastCreateErrorTime", //
+ "CreateErrorCount" //
//
};
diff --git a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java
index 9817f82acb..f50990aa49 100644
--- a/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java
+++ b/src/main/java/com/alibaba/druid/stat/JdbcSqlStat.java
@@ -49,6 +49,8 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
private final AtomicLong executeSpanNanoMax = new AtomicLong();
private final AtomicLong runningCount = new AtomicLong(0L);
private final AtomicLong concurrentMax = new AtomicLong();
+ private final AtomicLong resultSetHoldTimeNano = new AtomicLong();
+
private String name;
private String file;
private String dbType;
@@ -180,6 +182,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
histogram.reset();
this.lastSlowParameters = null;
inTransactionCount.set(0);
+ resultSetHoldTimeNano.set(0);
}
public long getConcurrentMax() {
@@ -393,6 +396,7 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
// 25 -
new ArrayType(SimpleType.LONG, true), //
SimpleType.STRING, //
+ SimpleType.LONG, //
};
String[] indexNames = {
@@ -433,7 +437,8 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
// 25 -
"Histogram", //
- "LastSlowParameters"
+ "LastSlowParameters",
+ "ResultSetHoldTime"
//
};
String[] indexDescriptions = indexNames;
@@ -455,30 +460,33 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
map.put("SQL", sql);
map.put("ExecuteCount", getExecuteCount());
map.put("ErrorCount", getErrorCount());
- map.put("TotalTime", getExecuteMillisTotal());
+ // 5 - 9
+ map.put("TotalTime", getExecuteMillisTotal());
map.put("LastTime", getExecuteLastStartTime());
map.put("MaxTimespan", getExecuteMillisMax());
map.put("LastError", JMXUtils.getErrorCompositeData(this.getExecuteErrorLast()));
map.put("EffectedRowCount", getUpdateCount());
- map.put("FetchRowCount", getFetchRowCount());
+ // 10 - 14
+ map.put("FetchRowCount", getFetchRowCount());
map.put("MaxTimespanOccurTime", getExecuteNanoSpanMaxOccurTime());
map.put("BatchSizeMax", getExecuteBatchSizeMax());
map.put("BatchSizeTotal", getExecuteBatchSizeTotal());
map.put("ConcurrentMax", getConcurrentMax());
- map.put("RunningCount", getRunningCount());
- map.put("Name", getName());
- map.put("File", getFile());
+ // 15 -
+ map.put("RunningCount", getRunningCount()); // 15
+ map.put("Name", getName()); // 16
+ map.put("File", getFile()); // 17
Throwable lastError = this.executeErrorLast;
if (lastError != null) {
- map.put("LastErrorMessage", lastError.getMessage());
- map.put("LastErrorClass", lastError.getClass().getName());
+ map.put("LastErrorMessage", lastError.getMessage()); // 18
+ map.put("LastErrorClass", lastError.getClass().getName()); // 19
- map.put("LastErrorStackTrace", IOUtils.getStackTrace(lastError));
- map.put("LastErrorTime", new Date(executeErrorLastTime));
+ map.put("LastErrorStackTrace", IOUtils.getStackTrace(lastError)); // 20
+ map.put("LastErrorTime", new Date(executeErrorLastTime)); // 21
} else {
map.put("LastErrorMessage", null);
map.put("LastErrorClass", null);
@@ -486,13 +494,13 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
map.put("LastErrorTime", null);
}
- map.put("DbType", dbType);
- map.put("URL", null);
- map.put("InTransactionCount", getInTransactionCount());
+ map.put("DbType", dbType); // 22
+ map.put("URL", null); // 23
+ map.put("InTransactionCount", getInTransactionCount()); // 24
- map.put("Histogram", this.histogram.toArray());
-
- map.put("LastSlowParameters", lastSlowParameters);
+ map.put("Histogram", this.histogram.toArray()); // 25
+ map.put("LastSlowParameters", lastSlowParameters); // 26
+ map.put("ResultSetHoldTime", getResultSetHoldTimeMilis()); // 26
return map;
}
@@ -511,4 +519,17 @@ public final class JdbcSqlStat implements JdbcSqlStatMBean {
executeErrorLast = error;
}
+
+ public long getResultSetHoldTimeMilis() {
+ return getResultSetHoldTimeNano() / (1000 * 1000);
+ }
+
+ public long getResultSetHoldTimeNano() {
+ return resultSetHoldTimeNano.get();
+ }
+
+ public void addResultSetHoldTimeNano(long nano) {
+ resultSetHoldTimeNano.addAndGet(nano);
+ }
+
}
diff --git a/src/test/java/com/alibaba/druid/bvt/pool/SpringFilterTest.java b/src/test/java/com/alibaba/druid/bvt/pool/SpringFilterTest.java
index 7b36079014..1268fe310b 100644
--- a/src/test/java/com/alibaba/druid/bvt/pool/SpringFilterTest.java
+++ b/src/test/java/com/alibaba/druid/bvt/pool/SpringFilterTest.java
@@ -16,6 +16,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
+import com.alibaba.druid.spring.IUserService;
+import com.alibaba.druid.spring.User;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
public class SpringFilterTest extends TestCase {
@@ -35,17 +37,37 @@ public class SpringFilterTest extends TestCase {
"com/alibaba/druid/pool/spring-config-1.xml");
DataSource dataSource = (DataSource) context.getBean("dataSource");
- Connection conn = dataSource.getConnection();
- Statement stmt = conn.createStatement();
- stmt.execute("select 1");
- stmt.execute("select 2");
- stmt.execute("select 1");
- stmt.close();
- conn.close();
+ {
+ Connection conn = dataSource.getConnection();
+ Statement stmt = conn.createStatement();
+ stmt.execute("CREATE TABLE sequence_seed (value INTEGER, name VARCHAR(50))");
+ stmt.close();
+ conn.close();
+ }
+ {
+ Connection conn = dataSource.getConnection();
+ Statement stmt = conn.createStatement();
+ stmt.execute("CREATE TABLE t_User (id BIGINT, name VARCHAR(50))");
+ stmt.close();
+ conn.close();
+ }
+ {
+ Connection conn = dataSource.getConnection();
+ Statement stmt = conn.createStatement();
+ stmt.execute("insert into sequence_seed (value ,name) values (0, 'druid-spring-test')");
+ stmt.close();
+ conn.close();
+ }
+
+ // user-service
+ IUserService service = (IUserService) context.getBean("user-service");
+ User user = new User();
+ user.setName("xx");
+ service.addUser(user);
TestFilter filter = (TestFilter) context.getBean("test-filter");
- Assert.assertEquals(1, filter.getConnectCount());
+ Assert.assertEquals(2, filter.getConnectCount());
context.close();
diff --git a/src/test/java/com/alibaba/druid/spring/ISequenceDao.java b/src/test/java/com/alibaba/druid/spring/ISequenceDao.java
new file mode 100644
index 0000000000..c8e31d71df
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/ISequenceDao.java
@@ -0,0 +1,8 @@
+package com.alibaba.druid.spring;
+
+public interface ISequenceDao {
+
+ boolean compareAndSet(String name, int value, int expect);
+
+ int getValue(String name);
+}
diff --git a/src/test/java/com/alibaba/druid/spring/ISequenceService.java b/src/test/java/com/alibaba/druid/spring/ISequenceService.java
new file mode 100644
index 0000000000..add42bb7ec
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/ISequenceService.java
@@ -0,0 +1,6 @@
+package com.alibaba.druid.spring;
+
+
+public interface ISequenceService {
+ long nextValue();
+}
diff --git a/src/test/java/com/alibaba/druid/spring/IUserDao.java b/src/test/java/com/alibaba/druid/spring/IUserDao.java
new file mode 100644
index 0000000000..fb7afeee35
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/IUserDao.java
@@ -0,0 +1,6 @@
+package com.alibaba.druid.spring;
+
+
+public interface IUserDao {
+ void addUser(User user);
+}
diff --git a/src/test/java/com/alibaba/druid/spring/IUserService.java b/src/test/java/com/alibaba/druid/spring/IUserService.java
new file mode 100644
index 0000000000..f01e714b9d
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/IUserService.java
@@ -0,0 +1,6 @@
+package com.alibaba.druid.spring;
+
+
+public interface IUserService {
+ void addUser(User user);
+}
diff --git a/src/test/java/com/alibaba/druid/spring/SequenceDao.java b/src/test/java/com/alibaba/druid/spring/SequenceDao.java
new file mode 100644
index 0000000000..4d8f0c76bc
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/SequenceDao.java
@@ -0,0 +1,29 @@
+package com.alibaba.druid.spring;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
+
+public class SequenceDao extends SqlMapClientDaoSupport implements ISequenceDao {
+
+ public boolean compareAndSet(String name, int value, int expect) {
+
+ Map parameters = new HashMap();
+ parameters.put("name", name);
+ parameters.put("value", value);
+ parameters.put("expect", expect);
+
+ int updateCount = getSqlMapClientTemplate().update("Sequence.compareAndSet", parameters);
+
+ return updateCount == 1;
+ }
+
+ public int getValue(String name) {
+ return (Integer) getSqlMapClientTemplate().queryForObject("Sequence.getValue", name);
+ }
+
+ public int getValueForUpdate(String name) {
+ return (Integer) getSqlMapClientTemplate().queryForObject("Sequence.getValueForUpdate", name);
+ }
+}
diff --git a/src/test/java/com/alibaba/druid/spring/SequenceService.java b/src/test/java/com/alibaba/druid/spring/SequenceService.java
new file mode 100644
index 0000000000..9d18a76048
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/SequenceService.java
@@ -0,0 +1,69 @@
+package com.alibaba.druid.spring;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+public class SequenceService implements SequenceServiceMBean, ISequenceService {
+
+ private ISequenceDao dao;
+ private String name = "druid-spring-test";
+
+ private String seed;
+
+ private AtomicInteger increment = new AtomicInteger();
+
+ public ISequenceDao getDao() {
+ return dao;
+ }
+
+ public void setDao(ISequenceDao dao) {
+ this.dao = dao;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSeed() {
+ return this.seed;
+ }
+
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
+ public long nextValue() {
+ if (seed == null) {
+ init();
+ }
+
+ int value = increment.getAndIncrement();
+
+ String text = seed + "9" + Integer.toString(value);
+
+ return Long.parseLong(text);
+ }
+
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
+ public synchronized void init() {
+ this.seed = nextSeed();
+ }
+
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
+ public synchronized String nextSeed() {
+ for (;;) {
+ int value = dao.getValue(name);
+ if (dao.compareAndSet(name, value + 1, value)) {
+ if (value == 0) {
+ return "";
+ } else {
+ return Integer.toString(value, 9);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/test/java/com/alibaba/druid/spring/SequenceServiceMBean.java b/src/test/java/com/alibaba/druid/spring/SequenceServiceMBean.java
new file mode 100644
index 0000000000..13ce6a55fa
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/SequenceServiceMBean.java
@@ -0,0 +1,6 @@
+package com.alibaba.druid.spring;
+
+
+public interface SequenceServiceMBean {
+
+}
diff --git a/src/test/java/com/alibaba/druid/spring/User.java b/src/test/java/com/alibaba/druid/spring/User.java
new file mode 100644
index 0000000000..21050f85f8
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/User.java
@@ -0,0 +1,25 @@
+package com.alibaba.druid.spring;
+
+public class User {
+
+ private long id;
+ private String name;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+
+}
diff --git a/src/test/java/com/alibaba/druid/spring/UserDao.java b/src/test/java/com/alibaba/druid/spring/UserDao.java
new file mode 100644
index 0000000000..664ac89d51
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/UserDao.java
@@ -0,0 +1,10 @@
+package com.alibaba.druid.spring;
+
+import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
+
+public class UserDao extends SqlMapClientDaoSupport implements IUserDao {
+
+ public void addUser(User user) {
+ getSqlMapClientTemplate().insert("User.insert", user);
+ }
+}
diff --git a/src/test/java/com/alibaba/druid/spring/UserService.java b/src/test/java/com/alibaba/druid/spring/UserService.java
new file mode 100644
index 0000000000..5bb33f198a
--- /dev/null
+++ b/src/test/java/com/alibaba/druid/spring/UserService.java
@@ -0,0 +1,33 @@
+package com.alibaba.druid.spring;
+
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+public class UserService implements IUserService {
+
+ private IUserDao dao;
+ private ISequenceService sequenceService;
+
+ @Transactional(propagation = Propagation.REQUIRED)
+ public void addUser(User user) {
+ user.setId(sequenceService.nextValue());
+ dao.addUser(user);
+ }
+
+ public IUserDao getDao() {
+ return dao;
+ }
+
+ public void setDao(IUserDao dao) {
+ this.dao = dao;
+ }
+
+ public ISequenceService getSequenceService() {
+ return sequenceService;
+ }
+
+ public void setSequenceService(ISequenceService sequenceService) {
+ this.sequenceService = sequenceService;
+ }
+
+}
diff --git a/src/test/resources/com/alibaba/druid/pool/Sequence.xml b/src/test/resources/com/alibaba/druid/pool/Sequence.xml
new file mode 100644
index 0000000000..d6cbd67eb8
--- /dev/null
+++ b/src/test/resources/com/alibaba/druid/pool/Sequence.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+ UPDATE sequence_seed
+ SET value = #value#
+ WHERE name = #name# AND value = #expect#
+
+
diff --git a/src/test/resources/com/alibaba/druid/pool/User.xml b/src/test/resources/com/alibaba/druid/pool/User.xml
new file mode 100644
index 0000000000..38b5d2f2e1
--- /dev/null
+++ b/src/test/resources/com/alibaba/druid/pool/User.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ insert into t_User (id, name) values (#id#, #name#)
+
+
diff --git a/src/test/resources/com/alibaba/druid/pool/ibatis-config-druid-test.xml b/src/test/resources/com/alibaba/druid/pool/ibatis-config-druid-test.xml
new file mode 100644
index 0000000000..29c36cb346
--- /dev/null
+++ b/src/test/resources/com/alibaba/druid/pool/ibatis-config-druid-test.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/com/alibaba/druid/pool/spring-config-1.xml b/src/test/resources/com/alibaba/druid/pool/spring-config-1.xml
index cb4de6ef20..05f9399abb 100644
--- a/src/test/resources/com/alibaba/druid/pool/spring-config-1.xml
+++ b/src/test/resources/com/alibaba/druid/pool/spring-config-1.xml
@@ -6,6 +6,28 @@
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-lazy-init="false">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -15,6 +37,7 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/
+
@@ -25,7 +48,7 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/
- jdbc:mock:
+ jdbc:derby:memory:spring-test;create=true
1
@@ -40,6 +63,7 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/
+
@@ -58,4 +82,11 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/
+
+
+
+
+
+
diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties
index 64b595c698..7fb1ab6b07 100644
--- a/src/test/resources/log4j.properties
+++ b/src/test/resources/log4j.properties
@@ -22,8 +22,7 @@ log4j.category.org.apache.catalina=ERROR
log4j.category.org.apache.struts.chain=ERROR
log4j.category.org.apache.jasper=INFO
log4j.category.org.apache.struts=INFO
-log4j.category.java.sql=DEBUG
-log4j.category.java.sql.ResultSet=DEBUG
+log4j.category.java.sql=ERROR
log4j.category.org.codehaus.xfire=INFO
log4j.category.httpclient=INFO
log4j.category.org.apache.struts.action.ActionServlet=ERROR