Skip to content

Commit

Permalink
Added explicit UoW to the EventTriggerCallback
Browse files Browse the repository at this point in the history
This improves the lock release timing when using transactions. It ensures that locks are only released when all of the underlying transactions are committed.
(cherry picked from commit 27413b1)
  • Loading branch information
abuijze committed May 4, 2012
1 parent 02c37a9 commit 870efe2
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,38 +31,28 @@
* @author Allard Buijze
* @since 1.1
*/
public class SpringTransactionalTriggerCallback implements EventTriggerCallback, InitializingBean {
public class SpringTransactionalTriggerCallback extends TransactionalEventTriggerCallback<TransactionStatus>
implements InitializingBean {

private final ThreadLocal<TransactionStatus> transactions = new ThreadLocal<TransactionStatus>();
private PlatformTransactionManager transactionManager;
private TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();

@Override
public void beforePublication(ApplicationEvent event) {
transactions.set(transactionManager.getTransaction(transactionDefinition));
protected TransactionStatus startUnderlyingTransaction(ApplicationEvent event) {
return transactionManager.getTransaction(transactionDefinition);
}

@Override
public void afterPublicationSuccess() {
try {
TransactionStatus status = transactions.get();
if (status.isNewTransaction()) {
transactionManager.commit(status);
}
} finally {
transactions.remove();
protected void commitUnderlyingTransaction(TransactionStatus tx) {
if (tx.isNewTransaction()) {
transactionManager.commit(tx);
}
}

@Override
public void afterPublicationFailure(RuntimeException cause) {
try {
TransactionStatus status = transactions.get();
if (status.isNewTransaction() && !status.isCompleted()) {
transactionManager.rollback(status);
}
} finally {
transactions.remove();
protected void rollbackUnderlyingTransaction(TransactionStatus tx) {
if (tx.isNewTransaction() && !tx.isCompleted()) {
transactionManager.rollback(tx);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package org.axonframework.eventhandling.scheduling;

import org.axonframework.domain.ApplicationEvent;
import org.axonframework.unitofwork.CurrentUnitOfWork;
import org.axonframework.unitofwork.DefaultUnitOfWork;
import org.axonframework.unitofwork.UnitOfWork;
import org.axonframework.unitofwork.UnitOfWorkListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Abstract implementation of the {@link EventTriggerCallback} interface that ensures a UnitOfWork is used to contain
* the transaction. This way, proper locking and unlocking ordering is guaranteed in combination with the underlying
* transaction.
*
* @param <T> The type of transaction status object used by the backing transaction manager
* @author Allard Buijze
* @since 1.3
*/
public abstract class TransactionalEventTriggerCallback<T> implements EventTriggerCallback {

private static final Logger logger = LoggerFactory.getLogger(TransactionalEventTriggerCallback.class);

@Override
public void beforePublication(ApplicationEvent event) {
UnitOfWork uow = DefaultUnitOfWork.startAndGet();
final T tx = startUnderlyingTransaction(event);
uow.registerListener(new UnitOfWorkListenerAdapter() {
@Override
public void onRollback(Throwable failureCause) {
logger.warn("Rolling back transaction due to exception.", failureCause);
rollbackUnderlyingTransaction(tx);
}

@Override
public void afterCommit() {
commitUnderlyingTransaction(tx);
}
});
}

@Override
public void afterPublicationSuccess() {
CurrentUnitOfWork.commit();
}

@Override
public void afterPublicationFailure(RuntimeException cause) {
CurrentUnitOfWork.get().rollback(cause);
}

/**
* Starts a transaction in the underlying transaction manager. The returned value will be passed as parameter to
* the {@link #commitUnderlyingTransaction(Object)} or {@link #rollbackUnderlyingTransaction(Object)} method.
*
* @param event the event for which a transaction should be started
* @return an object describing the underlying transaction.
*/
protected abstract T startUnderlyingTransaction(ApplicationEvent event);

/**
* Commits the transaction described by <code>tx</code> in the underlying transaction manager.
*
* @param tx The object returned by {@link #startUnderlyingTransaction(org.axonframework.domain.ApplicationEvent)}
*/
protected abstract void commitUnderlyingTransaction(T tx);

/**
* Rolls back the transaction described by <code>tx</code> in the underlying transaction manager.
*
* @param tx The object returned by {@link #startUnderlyingTransaction(org.axonframework.domain.ApplicationEvent)}
*/
protected abstract void rollbackUnderlyingTransaction(T tx);
}

0 comments on commit 870efe2

Please sign in to comment.