@Override public void begin(Handle handle) { try { if (!localStuff.containsKey(handle)) { boolean initial = handle.getConnection().getAutoCommit(); localStuff.putIfAbsent(handle, new LocalStuff(initial)); handle.getConnection().setAutoCommit(false); } } catch (SQLException e) { throw new TransactionException("Failed to start transaction", e); } }
@Override public boolean isInTransaction(Handle handle) { try { return !handle.getConnection().getAutoCommit(); } catch (SQLException e) { throw new TransactionException("Failed to test for transaction status", e); } }
/** * Called to test if a handle is in a transaction */ @Override public boolean isInTransaction(Handle handle) { try { return !handle.getConnection().getAutoCommit(); } catch (SQLException e) { throw new TransactionException("Failed to check status of transaction", e); } }
@Override public void savepoint(Handle handle, String name) { @SuppressWarnings("PMD.CloseResource") final Connection conn = handle.getConnection(); try { final Savepoint savepoint = conn.setSavepoint(name); localStuff.get(handle).getSavepoints().put(name, savepoint); } catch (SQLException e) { throw new TransactionException(String.format("Unable to create savepoint '%s'", name), e); } }
@Override public void rollback(Handle handle) { didTxnRollback.set(true); try { handle.getConnection().rollback(); } catch (SQLException e) { throw new TransactionException("Failed to rollback transaction", e); } finally { restoreAutoCommitState(handle); } }
@Override public void commit(Handle handle) { try { handle.getConnection().commit(); } catch (SQLException e) { throw new TransactionException("Failed to commit transaction", e); } finally { restoreAutoCommitState(handle); } }
boolean hasOpenedHandle() throws SQLException { for (Handle h : openedHandle) { if (!h.getConnection().isClosed()) { return true; } } return false; } }
@Override public void releaseSavepoint(Handle handle, String name) { @SuppressWarnings("PMD.CloseResource") final Connection conn = handle.getConnection(); try { final Savepoint savepoint = localStuff.get(handle).getSavepoints().remove(name); if (savepoint == null) { throw new TransactionException(String.format("Attempt to release non-existent savepoint, '%s'", name)); } conn.releaseSavepoint(savepoint); } catch (SQLException e) { throw new TransactionException(String.format("Unable to create savepoint %s", name), e); } }
@Override public void rollbackToSavepoint(Handle handle, String name) { @SuppressWarnings("PMD.CloseResource") final Connection conn = handle.getConnection(); try { final Savepoint savepoint = localStuff.get(handle).getSavepoints().remove(name); if (savepoint == null) { throw new TransactionException(String.format("Attempt to rollback to non-existent savepoint, '%s'", name)); } conn.rollback(savepoint); } catch (SQLException e) { throw new TransactionException(String.format("Unable to create savepoint %s", name), e); } }
private void restoreAutoCommitState(final Handle handle) { try { final LocalStuff stuff = localStuff.remove(handle); if (stuff != null) { handle.getConnection().setAutoCommit(stuff.getInitialAutocommit()); stuff.getSavepoints().clear(); } } catch (SQLException e) { throw new UnableToRestoreAutoCommitStateException(e); } finally { // prevent memory leak if rollback throws an exception localStuff.remove(handle); } }
SqlStatement(Handle handle, String sql) { super(handle); this.handle = handle; this.sql = sql; getContext() .setConnection(handle.getConnection()) .setRawSql(sql); }
@Test public void testDoubleOpen() throws Exception { assertThat(h.getConnection().getAutoCommit()).isTrue(); h.begin(); h.begin(); assertThat(h.getConnection().getAutoCommit()).isFalse(); h.commit(); assertThat(h.getConnection().getAutoCommit()).isTrue(); }
@Test public void testHandleReadOnly() throws Exception { try (Handle h = db.openHandle()) { assertThat(h.isReadOnly()).isFalse(); assertThat(h.getConnection().isReadOnly()).isFalse(); h.setReadOnly(true); assertThat(h.isReadOnly()).isTrue(); assertThat(h.getConnection().isReadOnly()).isTrue(); } }
@Test public void testThrowError() throws Exception { Error error = new Error("Transaction throws!"); Mockito.when(c.getAutoCommit()).thenReturn(true); Mockito.when(h.getConnection()).thenReturn(c); assertThatThrownBy(() -> new LocalTransactionHandler().inTransaction(h, x -> { throw error; })) .isSameAs(error); } }
@Override protected void before() throws Throwable { db = Jdbi.create(uri); if (installPlugins) { db.installPlugins(); } plugins.forEach(db::installPlugin); sharedHandle = db.open(); con = sharedHandle.getConnection(); try (Statement s = con.createStatement()) { // TODO legacy... s.execute("create table something (id identity primary key, name varchar(50), integerValue integer, intValue integer)"); } }
@Override protected void before() { db = Jdbi.create(uri); if (installPlugins) { db.installPlugins(); } plugins.forEach(db::installPlugin); sharedHandle = db.open(); con = sharedHandle.getConnection(); }
@Test public void testOpenNewSpiffy() throws Exception { final AtomicReference<Connection> c = new AtomicReference<>(); db.useExtension(Spiffy.class, spiffy -> { spiffy.insert(new Something(1, "Tim")); spiffy.insert(new Something(2, "Diego")); assertThat(spiffy.findNameById(2)).isEqualTo("Diego"); c.set(spiffy.getHandle().getConnection()); }); assertThat(c.get().isClosed()).isTrue(); }
@Transaction(readOnly = true) default boolean verifyReadOnly() throws SQLException { final Handle h = getHandle(); if (h.isReadOnly() != h.getConnection().isReadOnly()) { throw new AssertionError("didn't set"); } return h.isReadOnly(); }
@Test public void testRollbackFailDoesntLeak() throws Exception { final BoomHandler handler = new BoomHandler(); dbRule.getJdbi().setTransactionHandler(handler); final Handle h = dbRule.openHandle(); assertThat(h.isClosed()).isFalse(); handler.failRollback = true; assertThatThrownBy(() -> h.useTransaction(h2 -> h2.execute("insert into true"))) .isInstanceOf(UnableToCreateStatementException.class); assertThat(h.isInTransaction()) .describedAs("rollback failed but handle should still be in transaction").isTrue(); assertThatThrownBy(h::close) .isInstanceOf(CloseException.class); assertThat(h.isClosed()).isTrue(); assertThat(h.getConnection().isClosed()).isTrue(); }
@Test public void testCustomizeConnection() { Connection c = mock(Connection.class); dbRule.getJdbi().installPlugin(new JdbiPlugin() { @Override public Connection customizeConnection(Connection conn) { return c; } }); assertThat(c).isSameAs(dbRule.getJdbi().open().getConnection()); } }