From a64e30a62e47c8d05efbb5b5faf4fac7adee7684 Mon Sep 17 00:00:00 2001 From: bernd Date: Wed, 14 Nov 2012 21:24:31 +0100 Subject: [PATCH 05/25] Fix a bug where the BaseQueryImpl confuses connections when it uses different DataSources within one thread. --- .../src/net/lemnik/eodsql/impl/BaseQueryImpl.java | 17 ++- eodsql/test/net/lemnik/eodsql/EoDTestCase.java | 2 +- .../net/lemnik/eodsql/MultipleDataSourcesTest.java | 137 +++++++++++++++++++++ 3 files changed, 149 insertions(+), 7 deletions(-) create mode 100644 eodsql/test/net/lemnik/eodsql/MultipleDataSourcesTest.java diff --git a/eodsql/src/net/lemnik/eodsql/impl/BaseQueryImpl.java b/eodsql/src/net/lemnik/eodsql/impl/BaseQueryImpl.java index 52bc944..a2e6ee7 100644 --- a/eodsql/src/net/lemnik/eodsql/impl/BaseQueryImpl.java +++ b/eodsql/src/net/lemnik/eodsql/impl/BaseQueryImpl.java @@ -284,8 +284,13 @@ class BaseQueryImpl implements InvocationHandler { static class DataSourceConnectionSource implements ConnectionSource { - private static final ThreadLocal CONNECTION_UTILS = - new ThreadLocal(); + private static final ThreadLocal> + CONNECTION_UTILS = new ThreadLocal>() { + @Override + protected IdentityHashMap initialValue() { + return new IdentityHashMap(); + } + }; private final DataSource datasource; @@ -325,7 +330,7 @@ class BaseQueryImpl implements InvocationHandler { } public Connection getConnection() throws SQLException { - ConnectionUtil util = CONNECTION_UTILS.get(); + ConnectionUtil util = CONNECTION_UTILS.get().get(datasource); if(util == null || util.connection.isClosed()) { final Connection tmp = datasource.getConnection(); @@ -339,7 +344,7 @@ class BaseQueryImpl implements InvocationHandler { util = new ConnectionUtil(tmp); util.count++; - CONNECTION_UTILS.set(util); + CONNECTION_UTILS.get().put(datasource, util); } else { util.count++; } @@ -351,12 +356,12 @@ class BaseQueryImpl implements InvocationHandler { throws SQLException { if(connections.containsKey(connection)) { - final ConnectionUtil util = CONNECTION_UTILS.get(); + final ConnectionUtil util = CONNECTION_UTILS.get().get(datasource); if(--util.count <= 0) { connections.remove(connection); connection.close(); - CONNECTION_UTILS.remove(); + CONNECTION_UTILS.get().remove(datasource); } } } diff --git a/eodsql/test/net/lemnik/eodsql/EoDTestCase.java b/eodsql/test/net/lemnik/eodsql/EoDTestCase.java index 59faccb..d5f23ea 100644 --- a/eodsql/test/net/lemnik/eodsql/EoDTestCase.java +++ b/eodsql/test/net/lemnik/eodsql/EoDTestCase.java @@ -82,7 +82,7 @@ public abstract class EoDTestCase extends TestCase { } } - private static Properties loadBuildProperties() { + static Properties loadBuildProperties() { File propFile = new File("build.properties"); if(propFile.exists()) { return loadBuildProperties(propFile); diff --git a/eodsql/test/net/lemnik/eodsql/MultipleDataSourcesTest.java b/eodsql/test/net/lemnik/eodsql/MultipleDataSourcesTest.java new file mode 100644 index 0000000..27e8377 --- /dev/null +++ b/eodsql/test/net/lemnik/eodsql/MultipleDataSourcesTest.java @@ -0,0 +1,137 @@ +package net.lemnik.eodsql; + +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Properties; +import java.util.UUID; + +import javax.sql.DataSource; + +import junit.framework.TestCase; + +import org.apache.commons.dbcp.BasicDataSource; + +/** + * A test case which uses two data source in parallel within one thread. + * + * @author Bernd Rinn + */ +public class MultipleDataSourcesTest extends TestCase { + + private static String driverName; + + private static String url1; + + private static String url2; + + private static String user; + + private static String password; + + static { + driverName = System.getProperty("test.db.driver"); + url1 = System.getProperty("test.db.url") + "1"; + url2 = System.getProperty("test.db.url") + "2"; + user = System.getProperty("test.db.user"); + password = System.getProperty("test.db.password"); + + if (driverName == null) { + final Properties props = EoDTestCase.loadBuildProperties(); + driverName = props.getProperty("test.db.driver"); + url1 = props.getProperty("test.db.url") + "1"; + url2 = props.getProperty("test.db.url") + "2"; + user = props.getProperty("test.db.user"); + password = props.getProperty("test.db.password"); + } + } + + private BasicDataSource dataSource1; + + private BasicDataSource dataSource2; + + private TransactionTestQuery query1 = null; + + private LazySelectQuery query2 = null; + + private DataSource getDataSource1(boolean autoCommit) + throws ClassNotFoundException { + if (dataSource1 == null) { + dataSource1 = new BasicDataSource(); + Class.forName(driverName); + dataSource1.setDriverClassName(driverName); + + dataSource1.setUrl(url1); + dataSource1.setUsername(user); + dataSource1.setPassword(password); + } + dataSource1.setDefaultAutoCommit(autoCommit); + return dataSource1; + } + + private DataSource getDataSource2(boolean autoCommit) + throws ClassNotFoundException { + if (dataSource2 == null) { + dataSource2 = new BasicDataSource(); + Class.forName(driverName); + dataSource2.setDriverClassName(driverName); + + dataSource2.setUrl(url2); + dataSource2.setUsername(user); + dataSource2.setPassword(password); + } + dataSource2.setDefaultAutoCommit(autoCommit); + return dataSource2; + } + + private void createDBs() throws ClassNotFoundException { + query1 = QueryTool.getQuery(getDataSource1(true), TransactionTestQuery.class); + query1.createObjectsTable(); + query1.close(true); + + query2 = QueryTool + .getQuery(getDataSource2(true), LazySelectQuery.class); + query2.create(); + query2.close(); + } + + public void testMultipleDataSources() throws Exception { + createDBs(); + + query1 = QueryTool.getQuery(getDataSource1(true), TransactionTestQuery.class); + query2 = QueryTool + .getQuery(getDataSource2(true), LazySelectQuery.class); + + SimpleObject obj = new SimpleObject(); + UUID uuid = UUID.randomUUID(); + obj.id = uuid; + obj.data = "test"; + query1.insert(obj); + query1.commit(); + + final BigUserObject usr = new BigUserObject(); + usr.setId(1); + usr.setName("Klaus"); + usr.setPostCount(17); + Date joinDate = new GregorianCalendar(1990, 10, 3).getTime(); + usr.setJoinDate(joinDate); + usr.setPassword("ppp"); + usr.setOldPassword("ooo"); + query2.insert(usr); + + DataSet objs = query1.getObjects(); + assertEquals(1, objs.size()); + assertEquals(uuid, objs.get(0).id); + assertEquals("test", objs.get(0).data); + + final BigUserObject usr2 = new BigUserObject(); + usr2.setId(1); + query2.selectCoreInfo(usr2); + assertEquals(usr.getName(), usr2.getName()); + assertEquals(usr.getPostCount(), usr2.getPostCount()); + assertEquals(joinDate, usr.getJoinDate()); + + query1.close(); + query2.close(); + } + +} -- 1.8.0