Using AbstractTransactionalJUnit4SpringContextTests with commit halfway through
h2, hibernate, java, spring, transactions
Solution
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.
Problem
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); ```