use of org.jdbi.v3.core.transaction.SerializableTransactionRunner in project jdbi by jdbi.
the class TransactionTest method serializableTransaction.
@Test
public void serializableTransaction() throws Exception {
// tag::serializable[]
// Automatically rerun transactions
db.setTransactionHandler(new SerializableTransactionRunner());
// Set up some values
BiConsumer<Handle, Integer> insert = (h, i) -> h.execute("INSERT INTO ints(value) VALUES(?)", i);
handle.execute("CREATE TABLE ints (value INTEGER)");
insert.accept(handle, 10);
insert.accept(handle, 20);
// Run the following twice in parallel, and synchronize
ExecutorService executor = Executors.newCachedThreadPool();
CountDownLatch latch = new CountDownLatch(2);
Callable<Integer> sumAndInsert = () -> db.inTransaction(TransactionIsolationLevel.SERIALIZABLE, h -> {
// Both read initial state of table
int sum = h.select("SELECT sum(value) FROM ints").mapTo(int.class).findOnly();
// First time through, make sure neither transaction writes until both have read
latch.countDown();
latch.await();
// Now do the write.
insert.accept(h, sum);
return sum;
});
// Both of these would calculate 10 + 20 = 30, but that violates serialization!
Future<Integer> result1 = executor.submit(sumAndInsert);
Future<Integer> result2 = executor.submit(sumAndInsert);
// One of the transactions gets 30, the other will abort and automatically rerun.
// On the second attempt it will compute 10 + 20 + 30 = 60, seeing the update from its sibling.
// This assertion fails under any isolation level below SERIALIZABLE!
assertThat(result1.get() + result2.get()).isEqualTo(30 + 60);
executor.shutdown();
// end::serializable[]
}
Aggregations