Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using AbstractTransactionalJUnit4SpringContextTests with commit halfway through

We want a simple unit test that runs multiple threads - the idea is that the main thread commits a save to the database, then waits for a secondary thread to pick it up.

We're finding that the transaction has to be committed for the second Thread to be able to query the database and find the item. Otherwise, it won't exist.

We're trying to accomplish this using an H2 database, Hibernate to manage the access, and the unit test extends AbstractTransactionalJUnit4SpringContextTests.

When we try to commit() the existing transaction:

... // Create and save our model object

sessionFactory.getCurrentSession().getTransaction().commit();
sessionFactory.getCurrentSession().beginTransaction();

... // Create and start second Thread, query, etc.

We receive the error:

org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
    at org.springframework.orm.hibernate4.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:484)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:521)`

But when we try to extend only AbstractJUnit4SpringContextTests and use the @Transactional annotations:

@TransactionConfiguration(defaultRollback=false, transactionManager="transactionManager")
@Transactional()
public class DatabaseIntegrityTest extends AbstractJUnit4SpringContextTests {

With the same commit code from above, we receive:

org.hibernate.HibernateException: No Session found for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1041)

During our first call to getCurrentSession().

Is there a way to commit halfway-through a JUnit Transactional Spring test?

Further, when we try to create our own nested transaction using AbstractTransactionalJUnit4SpringContextTests, we receive:

org.hibernate.TransactionException: nested transactions not supported
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:152)
    at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1396)

Edit w/ Answer:

Thanks to axtavt, I was able to fix things by:

1) Extending AbstractJUnit4SpringContextTests

2) Using @Autowired for the PlatformTransactionManager:

   @Autowired
   protected PlatformTransactionManager transactionManager;

3) Putting my transactional code inside:

TransactionStatus status = transactionManager.getTransaction(null);
... // The Model-Saving Code
transactionManager.commit(status);
like image 616
Craig Otis Avatar asked Apr 12 '13 19:04

Craig Otis


1 Answers

So, you need to create multiple transactions inside your test method. As you can see, you cannot use AbstractTransactionalJUnit4SpringContextTests, because it creates a single transaction for the whole test method, and cannot use bare AbstractJUnit4SpringContextTests, because it creates no transactions at all.

The solution is to use AbstractJUnit4SpringContextTests and manage transactions inside your test method programmatically.

You need to inject PlatformTransactionManager into your test, create TransactionTemplate from it and use it to demarcate your transactions as described in 11.6 Programmatic transaction management.

like image 51
axtavt Avatar answered Oct 18 '22 13:10

axtavt