Question

I've got two methods annotated with @Transactional. The second method is called somewhere nested inside the first one.

Now I want the following behaviour to happen:

  • Every time the second, nested method is entered, a new nested transaction should be created. When that transaction is marked for a rollback, only that transaction should be rolled back.
  • But when the transaction of the outer method is marked for a rollback, every nested transaction inside — whether it's marked for a rollback or not — should be rolled back.

How do I have to set the Propagation values to achieve such functionality?


P. S.: I'm using a HibernateTransactionManager.

Was it helpful?

Solution

You need to use NESTED. Note that this propagation mode uses JDBC SavePoints in order to achieve this behavior, and that the nested behavior thus only works if the transaction is just a wrapper around the JDBC connection. It won't work for JTA transactions. See the Spring documentation for more details.

OTHER TIPS

One should clarify the default behaviour in Java Transactions. All nested transaction will not commit unless the parent commits. Read about it here http://en.wikibooks.org/wiki/Java_Persistence/Transactions

I'd propose to implement such functionality in separate threads, i.e. methods that you want to start in nested transactions - just start them in separate threads. It may look like following pseudo code:

//SomeService 
// Here we start an external transaction
@Transactional
    int processAllInTransaction() {
        List<Integer> jobIds = jobService.getJobs();
        if (!jobIds.isEmpty()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    jobIds.forEach(jobId ->
                            //Execute eveything in external transaction   
                            threadPool.execute(jobId)
                    );
                }
            }).start();

        } 
        return jobIds.size();
    }

//Method of Executor Service
void execute(final int jobId) {
    tasks.add(taskExecutor.submit(new Runnable() {
        void run() {
            someProcessor.processJob(jobId);
        }
    }));
}

//Method of another Service
@Transactional
public void processJob(int jobId) {
    //this will work in separate thransaction since was executed in another Theread
    someDao.doWorkInExternalTransaction(jobId);
}

If you really need to control external transaction - do nested transaction work in a single external transaction in new Theread and just wait for returned result from Thread and throw an Exception if needed

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top