Mr Jedi
Mr Jedi

Reputation: 34705

Spring app - run method on end of transaction?

I wondering it is possible to configure spring in way to fire particular method on end transaction?

For example I have service class with method

@Service
public class service implements IService
{
    @Resource
    private EntityDao entityDao;

    @Resource
    private SomeService someService;

    @Transactional
    @Override
    public void doThings()
    {
       entityDao.doSmthOnDb();
       someService.thisMethodFiresOnEndOfTransaction();
    }

}

and second service class

@Service
public class secondService implements ISecondService
{
  @Resource
  private IService service;

  @Transactional
  @Override
  public void method()
  {
  service.doThings();
  /*
  some other code that can break transaction
  */
  }
}

so if I call secondService.method() I want that someService.thisMethodFiresOnEndOfTransaction() will be fire only if transaction end successfully.

Is it possible in spring?

Upvotes: 1

Views: 3695

Answers (2)

Carlos Cuesta
Carlos Cuesta

Reputation: 1494

In Spring Boot, if you want to run a method at the end of a transaction, you can utilize the @Transactional annotation along with the TransactionSynchronizationManager class to register after-commit hooks

@Service
public class MyService {

  @Transactional
  public void myTransactionalMethod() {
    // Your transactional code here...

    // Register after-commit hook
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            runAfterTransaction();
        }
    });
  }

  public void runAfterTransaction() {
    // Your after-commit logic here...
    System.out.println("This method runs after the transaction is successfully committed!");
  }
}

Upvotes: 1

qwwdfsad
qwwdfsad

Reputation: 3207

Not sure, if it's good idea to delegate this to spring when you can add new bean as indirection layer between those services and delegate this thing to it.

But if you really don't have choice or want to do it with Spring, you can specify your own PlatformTransactionManager, which will delegate all calls to default manager, but also intercepts successful commit() calls. Example:

public class MyTransactionalManager implements PlatformTransactionManager {
// ... implementation via delegation skipped here
    @Override
    public void commit(TransactionStatus status) throws TransactionException {
        defaultManager.commit(status);
        // You might want to check status.isRollbackOnly() here
        someService.thisMethodFiresOnEndOfTransaction();
}

Now you can either replace default transaction manager in your application (then ::thisMethodFiresOnEndOfTransaction will be called after each transaction) or add it in context with some qualifier, then you should write something like this:

@Override
@Transactional(value = "myManager", rollbackFor = ...)  
public void method()

(And in the end of the answer I still think this is flawed approach and implementing it via just another bean is far better)

Upvotes: 2

Related Questions