Creating JPA session for background threads
hibernate, java, jpa, spring, transactions
Solution
I do not know of any Spring-ready solution for this. So, I think you need to implement one similar to the OpenEntityManagerInViewInterceptor class.
Basically, you need to use TransactionSynchronizationManager to bindResource() an instance of EntityManagerHolder for your thread when it is started and unbindResource() when your thread is finished.
The core part of OpenEntityManagerInViewInterceptor is:
if (TransactionSynchronizationManager.hasResource(getEntityManagerFactory())) {
...
}
else {
logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewInterceptor");
try {
EntityManager em = createEntityManager();
EntityManagerHolder emHolder = new EntityManagerHolder(em);
TransactionSynchronizationManager.bindResource(getEntityManagerFactory(), emHolder);
...
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
}
}
Please post the code here as an answer if you implemented it.
Problem
We use Hibernate through JPA and Spring to manage object persistence in our web application. We use open-session-in-view pattern to create sessions for threads responding to http requests. We also use some threads that are not generating views - they just wake up from time to time to do their job. That generates problems because they don't have session opened by default so they generate exceptions like ``` org.hibernate.SessionException: Session is closed! ``` or ``` could not initialize proxy - no Session ``` We found out that if every background thread invokes its logic in a method annotated with `@Transactional` there are no exceptions of this kind as `@Transactional` makes sure that thread has session when it's inside the transaction. It solved problems for some time but I don't think that it's a good solution - making long-running methods transactional causes problems because other threads can't see changes made in database until the transaction is committed. I created a java-pseudocode example to better illustrate my problem: ``` public class FirstThread { ... @Transactional public void processQueue() { for(element : queue){ if(elementCanBeProcessed(element)){ elementDao.saveIntoDatabase(element); secondThread.addToQueue(element.getId()); } } } private boolean elementCanBeProcessed(element){ //code that gets a few objects from database and processes them } } ``` If I annotate the whole `processQueue` method with `@Transactional` the changes made in ``` elementDao.saveIntoDatabase(element); ``` won't be seen in `secondThread` until the transaction is committed (so until the whole queue is processed). If I don't do that then the thread won't have session inside the `elementCanBeProcessed` and it won't be able to access the database. I also can't annotate `elementCanBeProcessed` instead because it's a private method in this class and I would have to move this into another class so that Spring proxy could work. Is it possible to bind session to thread without making the whole method transactional? How should I manage sessions and transactions in background threads like that one?