DKT
DKT

Reputation: 169

TransactionTemplate vs @Transactional(propagation = Propagation.REQUIRES_NEW)

could someone please explain why the first unit test class works whereas the second test class fails with a lock wait timeout error?

First test class:

public class Test1 extends AbstractTransactionalJUnit4SpringContextTests {

    @Before
    public void setUp() {
       // do stuff through hibernate to populate database with test data
    }

    @Test
    @Transactional(propagation = Propagation.NEVER)
    public void testDeleteObject() {

    TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            try {
               // execute sql that deletes data populated in setUp() [i.e. this will require locks on the objects].
            }
        });
    }
}

Second Test class [Get a lock wait timeout error]:

public class Test2 extends AbstractTransactionalJUnit4SpringContextTests {

    @Before
    public void setUp() {
       // do stuff through hibernate to populate database with test data
    }

    @Test
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void testObject() {

    // execute sql that deletes data populated in setUp() [i.e. this will require locks on the objects].

    }
}

I understand that the second test class fails because the two transaction are fighting for the same locks but neither can give up the locks due to its in_progress transaction state. What I'm confused about is why the first test class succeeds in executing the sql. I'm probably understanding this wrong, but doesn't a new transaction also gets created when the transactionTemplate executes the transaction callback? In that case, shouldn't the same thing happen (lock wait timeout)?

Upvotes: 3

Views: 10055

Answers (2)

Milanka
Milanka

Reputation: 1842

TransactionTemplate does not create a new transaction by default. The default propagation behaviour is PROPAGATION_REQUIRED. In your first case there are no locking issues, because setup and deletion are done in the same transaction.

You can see when new transactions are created or existing transactions reused by setting log level to DEBUG for class org.springframework.orm.jpa.JpaTransactionManager (or even for the whole org.springframework package).

Javadoc for propagation behaviour

Upvotes: 2

mrembisz
mrembisz

Reputation: 12880

A deadlock occurs only if there are two or more connections accessing the same data. In case of test case annotated with propagation NEVER you've got only one transaction, one created by TransactionTemplate.

The second case is a bit fuzzy to me. An exception means there are two concurrent connections/transactions - one for setUp and one for testObject. Propagation REQUIRES_NEW indeed enforces another connection even if there is one detected but I would expect setUp to be launched within this transaction as well. You may try to get rid of @Transactional on testObject. AbstractTransactionalJUnit4SpringContextTests is annotated with @Transactional itself with default propagation which is REQUIRED I believe.

Upvotes: 1

Related Questions