@Override public void endThreadConnection(DatabaseConnection connection) throws SQLException { connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); }
@Override public void endThreadConnection(DatabaseConnection connection) throws SQLException { connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); }
@Override public void clearSpecialConnection(DatabaseConnection connection) { cs.clearSpecialConnection(connection); }
@Override public void close() throws Exception { try { if (autoCommitAtStart) { connection.setAutoCommit(true); } } finally { connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); } } }
private <CT> CT doCallBatchTasks(ConnectionSource connectionSource, Callable<CT> callable) throws SQLException { DatabaseConnection connection = connectionSource.getReadWriteConnection(tableInfo.getTableName()); try { /* * We are using a thread-local boolean to detect whether we are in the middle of running a number of * changes. This disables the dao change notification for every batched call. */ localIsInBatchMode.set(true); /* * We need to save the connection because we are going to be disabling auto-commit on it and we don't want * pooled connection factories to give us another connection where auto-commit might still be enabled. */ boolean saved = connectionSource.saveSpecialConnection(connection); return doCallBatchTasks(connection, saved, callable); } finally { // even if the save-special returned false, we need to clear it to decrement the usage counter connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); localIsInBatchMode.set(false); if (dao != null) { // only at the end is the DAO notified of changes dao.notifyChanges(); } } }
private <CT> CT doCallBatchTasks(ConnectionSource connectionSource, Callable<CT> callable) throws SQLException { boolean saved = false; DatabaseConnection connection = connectionSource.getReadWriteConnection(tableInfo.getTableName()); try { /* * We are using a thread-local boolean to detect whether we are in the middle of running a number of * changes. This disables the dao change notification for every batched call. */ localIsInBatchMode.set(true); /* * We need to save the connection because we are going to be disabling auto-commit on it and we don't want * pooled connection factories to give us another connection where auto-commit might still be enabled. */ saved = connectionSource.saveSpecialConnection(connection); return doCallBatchTasks(connection, saved, callable); } finally { if (saved) { connectionSource.clearSpecialConnection(connection); } connectionSource.releaseConnection(connection); localIsInBatchMode.set(false); if (dao != null) { // only at the end is the DAO notified of changes dao.notifyChanges(); } } }
/** * Same as {@link #callInTransaction(ConnectionSource, Callable)} except this has a table-name. * * <p> * WARNING: it is up to you to properly synchronize around this method if multiple threads are using a * connection-source which works gives out a single-connection. The reason why this is necessary is that multiple * operations are performed on the connection and race-conditions will exist with multiple threads working on the * same connection. * </p> */ public static <T> T callInTransaction(String tableName, final ConnectionSource connectionSource, final Callable<T> callable) throws SQLException { DatabaseConnection connection = connectionSource.getReadWriteConnection(tableName); try { boolean saved = connectionSource.saveSpecialConnection(connection); return callInTransaction(connection, saved, connectionSource.getDatabaseType(), callable); } finally { // we should clear aggressively connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); } }
/** * Same as {@link #callInTransaction(ConnectionSource, Callable)} except this has a table-name. * * <p> * WARNING: it is up to you to properly synchronize around this method if multiple threads are using a * connection-source which works gives out a single-connection. The reason why this is necessary is that multiple * operations are performed on the connection and race-conditions will exist with multiple threads working on the * same connection. * </p> */ public static <T> T callInTransaction(String tableName, final ConnectionSource connectionSource, final Callable<T> callable) throws SQLException { DatabaseConnection connection = connectionSource.getReadWriteConnection(tableName); try { boolean saved = connectionSource.saveSpecialConnection(connection); return callInTransaction(connection, saved, connectionSource.getDatabaseType(), callable); } finally { // we should clear aggressively connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); } }
@Test public void testTransactionManagerSavePointNull() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(false); expect(conn.setSavePoint(isA(String.class))).andReturn(null); conn.commit(null); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(null)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn); TransactionManager tm = new TransactionManager(connectionSource); tm.callInTransaction(new Callable<Void>() { @Override public Void call() { return null; } }); verify(connectionSource, conn); }
@Test public void testCallBatchTasksNoAutoCommit() throws Exception { TableInfo<Foo, String> tableInfo = new TableInfo<Foo, String>(databaseType, Foo.class); ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection connection = createMock(DatabaseConnection.class); expect(connectionSource.isSingleConnection("foo")).andReturn(false); expect(connectionSource.getReadWriteConnection("foo")).andReturn(connection); expect(connectionSource.saveSpecialConnection(connection)).andReturn(false); connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); expect(connection.isAutoCommitSupported()).andReturn(false); StatementExecutor<Foo, String> statementExec = new StatementExecutor<Foo, String>(databaseType, tableInfo, null); replay(connectionSource, connection); final AtomicBoolean called = new AtomicBoolean(false); statementExec.callBatchTasks(connectionSource, new Callable<Void>() { @Override public Void call() { called.set(true); return null; } }); assertTrue(called.get()); verify(connectionSource, connection); }
@Test public void testCallBatchTasksAutoCommitFalse() throws Exception { TableInfo<Foo, String> tableInfo = new TableInfo<Foo, String>(databaseType, Foo.class); ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection connection = createMock(DatabaseConnection.class); expect(connectionSource.isSingleConnection("foo")).andReturn(false); expect(connectionSource.getReadWriteConnection("foo")).andReturn(connection); expect(connectionSource.saveSpecialConnection(connection)).andReturn(false); connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); expect(connection.isAutoCommitSupported()).andReturn(true); expect(connection.isAutoCommit()).andReturn(false); StatementExecutor<Foo, String> statementExec = new StatementExecutor<Foo, String>(databaseType, tableInfo, null); replay(connectionSource, connection); final AtomicBoolean called = new AtomicBoolean(false); statementExec.callBatchTasks(connectionSource, new Callable<Void>() { @Override public Void call() { called.set(true); return null; } }); assertTrue(called.get()); verify(connectionSource, connection); }
@Test public void testTransactionManagerAutoCommitOn() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(true); expect(conn.isAutoCommit()).andReturn(true); conn.setAutoCommit(false); Savepoint savePoint = createMock(Savepoint.class); expect(savePoint.getSavepointName()).andReturn("name").anyTimes(); expect(conn.setSavePoint(isA(String.class))).andReturn(savePoint); conn.commit(savePoint); conn.setAutoCommit(true); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(null)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn, savePoint); TransactionManager tm = new TransactionManager(connectionSource); tm.callInTransaction(new Callable<Void>() { @Override public Void call() { return null; } }); verify(connectionSource, conn, savePoint); }
@Test public void testTransactionManagerTableName() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(false); Savepoint savePoint = createMock(Savepoint.class); expect(savePoint.getSavepointName()).andReturn("name").anyTimes(); expect(conn.setSavePoint(isA(String.class))).andReturn(savePoint); conn.commit(savePoint); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(FOO_TABLE_NAME)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn, savePoint); TransactionManager tm = new TransactionManager(connectionSource); tm.callInTransaction(FOO_TABLE_NAME, new Callable<Void>() { @Override public Void call() { return null; } }); verify(connectionSource, conn, savePoint); }
@Test public void testTransactionManager() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(false); Savepoint savePoint = createMock(Savepoint.class); expect(savePoint.getSavepointName()).andReturn("name").anyTimes(); expect(conn.setSavePoint(isA(String.class))).andReturn(savePoint); conn.commit(savePoint); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(null)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn, savePoint); TransactionManager tm = new TransactionManager(connectionSource); tm.callInTransaction(new Callable<Void>() { @Override public Void call() { return null; } }); verify(connectionSource, conn, savePoint); }
@Test public void testTransactionManagerAutoCommitSupported() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(true); expect(conn.isAutoCommit()).andReturn(false); Savepoint savePoint = createMock(Savepoint.class); expect(savePoint.getSavepointName()).andReturn("name").anyTimes(); expect(conn.setSavePoint(isA(String.class))).andReturn(savePoint); conn.commit(savePoint); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(null)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn, savePoint); TransactionManager tm = new TransactionManager(connectionSource); tm.callInTransaction(new Callable<Void>() { @Override public Void call() { return null; } }); verify(connectionSource, conn, savePoint); }
@Test public void testCallBatchTasksAutoCommitTrueSynchronized() throws Exception { TableInfo<Foo, String> tableInfo = new TableInfo<Foo, String>(databaseType, Foo.class); ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection connection = createMock(DatabaseConnection.class); expect(connectionSource.isSingleConnection("foo")).andReturn(true); expect(connectionSource.getReadWriteConnection("foo")).andReturn(connection); expect(connectionSource.saveSpecialConnection(connection)).andReturn(false); connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); expect(connection.isAutoCommitSupported()).andReturn(true); expect(connection.isAutoCommit()).andReturn(true); connection.setAutoCommit(false); connection.setAutoCommit(true); StatementExecutor<Foo, String> statementExec = new StatementExecutor<Foo, String>(databaseType, tableInfo, null); replay(connectionSource, connection); final AtomicBoolean called = new AtomicBoolean(false); statementExec.callBatchTasks(connectionSource, new Callable<Void>() { @Override public Void call() { called.set(true); return null; } }); assertTrue(called.get()); verify(connectionSource, connection); }
@Test public void testTransactionManagerRollbackNullSavePoint() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(false); expect(conn.setSavePoint(isA(String.class))).andReturn(null); conn.rollback(null); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(null)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn); TransactionManager tm = new TransactionManager(connectionSource); try { tm.callInTransaction(new Callable<Void>() { @Override public Void call() throws Exception { throw new SQLException("you better roll back!!"); } }); fail("expected an exception"); } catch (SQLException e) { // expected } verify(connectionSource, conn); }
@Test public void testCallBatchTasksAutoCommitTrue() throws Exception { TableInfo<Foo, String> tableInfo = new TableInfo<Foo, String>(databaseType, Foo.class); ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection connection = createMock(DatabaseConnection.class); expect(connectionSource.isSingleConnection("foo")).andReturn(false); expect(connectionSource.getReadWriteConnection("foo")).andReturn(connection); expect(connectionSource.saveSpecialConnection(connection)).andReturn(false); connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); expect(connection.isAutoCommitSupported()).andReturn(true); expect(connection.isAutoCommit()).andReturn(true); connection.setAutoCommit(false); connection.setAutoCommit(true); StatementExecutor<Foo, String> statementExec = new StatementExecutor<Foo, String>(databaseType, tableInfo, null); replay(connectionSource, connection); final AtomicBoolean called = new AtomicBoolean(false); statementExec.callBatchTasks(connectionSource, new Callable<Void>() { @Override public Void call() { called.set(true); return null; } }); assertTrue(called.get()); verify(connectionSource, connection); }
@Test public void testTransactionManagerRollbackOtherException() throws Exception { ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection conn = createMock(DatabaseConnection.class); expect(conn.isAutoCommitSupported()).andReturn(false); Savepoint savePoint = createMock(Savepoint.class); expect(savePoint.getSavepointName()).andReturn("name").anyTimes(); expect(conn.setSavePoint(isA(String.class))).andReturn(savePoint); conn.rollback(savePoint); expect(connectionSource.getDatabaseType()).andReturn(databaseType); expect(connectionSource.getReadWriteConnection(null)).andReturn(conn); expect(connectionSource.saveSpecialConnection(conn)).andReturn(true); connectionSource.clearSpecialConnection(conn); connectionSource.releaseConnection(conn); replay(connectionSource, conn, savePoint); TransactionManager tm = new TransactionManager(connectionSource); try { tm.callInTransaction(new Callable<Void>() { @Override public Void call() throws Exception { throw new Exception("you better roll back!!"); } }); fail("expected an exception"); } catch (Exception e) { // expected } verify(connectionSource, conn, savePoint); }
@Test public void testCallBatchTasksAutoCommitTrueThrow() throws Exception { TableInfo<Foo, String> tableInfo = new TableInfo<Foo, String>(databaseType, Foo.class); ConnectionSource connectionSource = createMock(ConnectionSource.class); DatabaseConnection connection = createMock(DatabaseConnection.class); expect(connectionSource.isSingleConnection("foo")).andReturn(false); expect(connectionSource.getReadWriteConnection("foo")).andReturn(connection); expect(connectionSource.saveSpecialConnection(connection)).andReturn(false); connectionSource.clearSpecialConnection(connection); connectionSource.releaseConnection(connection); expect(connection.isAutoCommitSupported()).andReturn(true); expect(connection.isAutoCommit()).andReturn(true); connection.setAutoCommit(false); connection.setAutoCommit(true); StatementExecutor<Foo, String> statementExec = new StatementExecutor<Foo, String>(databaseType, tableInfo, null); replay(connectionSource, connection); try { statementExec.callBatchTasks(connectionSource, new Callable<Void>() { @Override public Void call() throws Exception { throw new Exception("expected"); } }); fail("Should have thrown"); } catch (Exception e) { // expected } verify(connectionSource, connection); }