/** * Executes the given {@code task} in a new {@link Transaction}. The transaction is committed when the task * completes normally, and rolled back when it throws an exception. * * @param task The task to execute */ default void executeInTransaction(Runnable task) { Transaction transaction = startTransaction(); try { task.run(); transaction.commit(); } catch (Throwable e) { transaction.rollback(); throw e; } }
/** * Invokes the given {@code supplier} in a transaction managed by the current TransactionManager. Upon completion * of the call, the transaction will be committed in the case of a regular return value, or rolled back in case an * exception occurred. * <p> * This method is an alternative to {@link #executeInTransaction(Runnable)} in cases where a result needs to be * returned from the code to be executed transactionally. * * @param supplier The supplier of the value to return * @param <T> The type of value to return * @return The value returned by the supplier */ default <T> T fetchInTransaction(Supplier<T> supplier) { Transaction transaction = startTransaction(); try { T result = supplier.get(); transaction.commit(); return result; } catch (Throwable e) { transaction.rollback(); throw e; } } }
/** * Creates a statement to read domain event entries for an aggregate with given identifier starting with the first * entry having a sequence number that is equal or larger than the given {@code firstSequenceNumber}. * * @param connection The connection to the database. * @param identifier The identifier of the aggregate. * @param firstSequenceNumber The expected sequence number of the first returned entry. * @param batchSize The number of items to include in the batch * @return A {@link PreparedStatement} that returns event entries for the given query when executed. * * @throws SQLException when an exception occurs while creating the prepared statement. */ protected PreparedStatement readEventData(Connection connection, String identifier, long firstSequenceNumber, int batchSize) throws SQLException { Transaction tx = transactionManager.startTransaction(); try { final String sql = "SELECT " + trackedEventFields() + " FROM " + schema.domainEventTable() + " WHERE " + schema.aggregateIdentifierColumn() + " = ? AND " + schema.sequenceNumberColumn() + " >= ? AND " + schema.sequenceNumberColumn() + " < ? ORDER BY " + schema.sequenceNumberColumn() + " ASC"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, identifier); preparedStatement.setLong(2, firstSequenceNumber); preparedStatement.setLong(3, firstSequenceNumber + batchSize); return preparedStatement; } finally { tx.commit(); } }
@Override public Object handle(UnitOfWork<? extends T> unitOfWork, InterceptorChain interceptorChain) throws Exception { Transaction transaction = transactionManager.startTransaction(); unitOfWork.onCommit(u -> transaction.commit()); unitOfWork.onRollback(u -> transaction.rollback()); return interceptorChain.proceed(); } }
@Test public void testHandlerIsInvokedInTransactionScope() throws Exception { CountDownLatch countDownLatch = new CountDownLatch(1); AtomicInteger counter = new AtomicInteger(); AtomicInteger counterAtHandle = new AtomicInteger(); when(mockTransactionManager.startTransaction()).thenAnswer(i -> { counter.incrementAndGet(); return mockTransaction; }); doAnswer(i -> counter.decrementAndGet()).when(mockTransaction).rollback(); doAnswer(i -> counter.decrementAndGet()).when(mockTransaction).commit(); doAnswer(invocation -> { counterAtHandle.set(counter.get()); countDownLatch.countDown(); return null; }).when(mockHandler).handle(any()); testSubject.start(); // give it a bit of time to start Thread.sleep(200); eventBus.publish(createEvents(2)); assertTrue("Expected Handler to have received 2 published events", countDownLatch.await(5, TimeUnit.SECONDS)); assertEquals(1, counterAtHandle.get()); }
/** * Attach a transaction to this Unit of Work, using the given {@code transactionManager}. The transaction will be * managed in the lifecycle of this Unit of Work. Failure to start a transaction will cause this Unit of Work * to be rolled back. * * @param transactionManager The Transaction Manager to create, commit and/or rollback the transaction */ default void attachTransaction(TransactionManager transactionManager) { try { Transaction transaction = transactionManager.startTransaction(); onCommit(u -> transaction.commit()); onRollback(u -> transaction.rollback()); } catch (Throwable t) { rollback(t); throw t; } }
mockTransaction = mock(Transaction.class); mockTransactionManager = mock(TransactionManager.class); when(mockTransactionManager.startTransaction()).thenReturn(mockTransaction); when(mockTransactionManager.fetchInTransaction(any(Supplier.class))).thenAnswer(i -> { Supplier s = i.getArgument(0);
@Override protected void storeEvents(EventMessage<?>... events) { UnitOfWork<?> unitOfWork = CurrentUnitOfWork.get(); Transaction transaction = transactionManager.startTransaction(); unitOfWork.onCommit(u -> transaction.commit()); unitOfWork.onRollback(u -> transaction.rollback()); super.storeEvents(events); } }
/** * Executes the given {@code task} in a new {@link Transaction}. The transaction is committed when the task * completes normally, and rolled back when it throws an exception. * * @param task The task to execute */ default void executeInTransaction(Runnable task) { Transaction transaction = startTransaction(); try { task.run(); transaction.commit(); } catch (Throwable e) { transaction.rollback(); throw e; } }
/** * Executes the given {@code task} in a new {@link Transaction}. The transaction is committed when the task * completes normally, and rolled back when it throws an exception. * * @param task The task to execute */ default void executeInTransaction(Runnable task) { Transaction transaction = startTransaction(); try { task.run(); transaction.commit(); } catch (Throwable e) { transaction.rollback(); throw e; } }
/** * Invokes the given {@code supplier} in a transaction managed by the current TransactionManager. Upon completion * of the call, the transaction will be committed in the case of a regular return value, or rolled back in case an * exception occurred. * <p> * This method is an alternative to {@link #executeInTransaction(Runnable)} in cases where a result needs to be * returned from the code to be executed transactionally. * * @param supplier The supplier of the value to return * @param <T> The type of value to return * @return The value returned by the supplier */ default <T> T fetchInTransaction(Supplier<T> supplier) { Transaction transaction = startTransaction(); try { T result = supplier.get(); transaction.commit(); return result; } catch (Throwable e) { transaction.rollback(); throw e; } } }
/** * Invokes the given {@code supplier} in a transaction managed by the current TransactionManager. Upon completion * of the call, the transaction will be committed in the case of a regular return value, or rolled back in case an * exception occurred. * <p> * This method is an alternative to {@link #executeInTransaction(Runnable)} in cases where a result needs to be * returned from the code to be executed transactionally. * * @param supplier The supplier of the value to return * @param <T> The type of value to return * @return The value returned by the supplier */ default <T> T fetchInTransaction(Supplier<T> supplier) { Transaction transaction = startTransaction(); try { T result = supplier.get(); transaction.commit(); return result; } catch (Throwable e) { transaction.rollback(); throw e; } } }
/** * Creates a statement to read domain event entries for an aggregate with given identifier starting with the first * entry having a sequence number that is equal or larger than the given {@code firstSequenceNumber}. * * @param connection The connection to the database. * @param identifier The identifier of the aggregate. * @param firstSequenceNumber The expected sequence number of the first returned entry. * @param batchSize The number of items to include in the batch * @return A {@link PreparedStatement} that returns event entries for the given query when executed. * @throws SQLException when an exception occurs while creating the prepared statement. */ protected PreparedStatement readEventData(Connection connection, String identifier, long firstSequenceNumber, int batchSize) throws SQLException { Transaction tx = transactionManager.startTransaction(); try { final String sql = "SELECT " + trackedEventFields() + " FROM " + schema.domainEventTable() + " WHERE " + schema.aggregateIdentifierColumn() + " = ? AND " + schema.sequenceNumberColumn() + " >= ? AND " + schema.sequenceNumberColumn() + " < ? ORDER BY " + schema.sequenceNumberColumn() + " ASC"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, identifier); preparedStatement.setLong(2, firstSequenceNumber); preparedStatement.setLong(3, firstSequenceNumber + batchSize); return preparedStatement; } finally { tx.commit(); } }
/** * Creates a statement to read domain event entries for an aggregate with given identifier starting with the first * entry having a sequence number that is equal or larger than the given {@code firstSequenceNumber}. * * @param connection The connection to the database. * @param identifier The identifier of the aggregate. * @param firstSequenceNumber The expected sequence number of the first returned entry. * @param batchSize The number of items to include in the batch * @return A {@link PreparedStatement} that returns event entries for the given query when executed. * * @throws SQLException when an exception occurs while creating the prepared statement. */ protected PreparedStatement readEventData(Connection connection, String identifier, long firstSequenceNumber, int batchSize) throws SQLException { Transaction tx = transactionManager.startTransaction(); try { final String sql = "SELECT " + trackedEventFields() + " FROM " + schema.domainEventTable() + " WHERE " + schema.aggregateIdentifierColumn() + " = ? AND " + schema.sequenceNumberColumn() + " >= ? AND " + schema.sequenceNumberColumn() + " < ? ORDER BY " + schema.sequenceNumberColumn() + " ASC"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, identifier); preparedStatement.setLong(2, firstSequenceNumber); preparedStatement.setLong(3, firstSequenceNumber + batchSize); return preparedStatement; } finally { tx.commit(); } }
@Override public Object handle(UnitOfWork<? extends T> unitOfWork, InterceptorChain interceptorChain) throws Exception { Transaction transaction = transactionManager.startTransaction(); unitOfWork.onCommit(u -> transaction.commit()); unitOfWork.onRollback(u -> transaction.rollback()); return interceptorChain.proceed(); } }
@Override public Object handle(UnitOfWork<? extends T> unitOfWork, InterceptorChain interceptorChain) throws Exception { Transaction transaction = transactionManager.startTransaction(); unitOfWork.onCommit(u -> transaction.commit()); unitOfWork.onRollback(u -> transaction.rollback()); return interceptorChain.proceed(); } }
/** * Attach a transaction to this Unit of Work, using the given {@code transactionManager}. The transaction will be * managed in the lifecycle of this Unit of Work. Failure to start a transaction will cause this Unit of Work * to be rolled back. * * @param transactionManager The Transaction Manager to create, commit and/or rollback the transaction */ default void attachTransaction(TransactionManager transactionManager) { try { Transaction transaction = transactionManager.startTransaction(); onCommit(u -> transaction.commit()); onRollback(u -> transaction.rollback()); } catch (Throwable t) { rollback(t); throw t; } }
/** * Attach a transaction to this Unit of Work, using the given {@code transactionManager}. The transaction will be * managed in the lifecycle of this Unit of Work. Failure to start a transaction will cause this Unit of Work * to be rolled back. * * @param transactionManager The Transaction Manager to create, commit and/or rollback the transaction */ default void attachTransaction(TransactionManager transactionManager) { try { Transaction transaction = transactionManager.startTransaction(); onCommit(u -> transaction.commit()); onRollback(u -> transaction.rollback()); } catch (Throwable t) { rollback(t); throw t; } }