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);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With