我们通过 JPA 和 Spring 使用 Hibernate 来管理 Web 应用程序中的对象持久性。我们使用 open-session-in-view 模式为响应 http 请求的线程创建 session 。我们还使用了一些不生成 View 的线程——它们只是不时地唤醒来完成它们的工作。这会产生问题,因为它们默认情况下没有打开 session ,所以它们会产生类似
的异常org.hibernate.SessionException: Session is closed!
或
could not initialize proxy - no Session
我们发现,如果每个后台线程都在用 @Transactional
注释的方法中调用其逻辑,则不会出现此类异常,因为 @Transactional
确保线程具有 session 在事务内时。
它解决了一段时间的问题,但我认为这不是一个好的解决方案 - 使长时间运行的方法成为事务性的会导致问题,因为在提交事务之前其他线程无法看到数据库中所做的更改。
我创建了一个 java 伪代码示例来更好地说明我的问题:
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
}
}
如果我用 @Transactional
注释整个 processQueue
方法
elementDao.saveIntoDatabase(element);
在提交事务之前不会在 secondThread
中看到(因此直到处理完整个队列)。如果我不这样做,那么线程将不会在 elementCanBeProcessed
中进行 session ,并且它将无法访问数据库。我也不能注释 elementCanBeProcessed
,因为它是此类中的私有(private)方法,我必须将它移到另一个类中,以便 Spring 代理可以工作。
是否可以将 session 绑定(bind)到线程而不使整个方法成为事务性的?我应该如何管理后台线程中的 session 和事务?
最佳答案
这是我在阅读 Amir Moghimi 的 answer 后编写的代码. 这似乎有点“hacky”,因为文档说典型的应用程序代码不应直接使用 EntityManagerHolder 和 TransactionSynchronizationManager。
@Service
public class DatabaseSessionManager {
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
public void bindSession() {
if (!TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));
}
}
public void unbindSession() {
EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager
.unbindResource(entityManagerFactory);
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
}
}
它似乎在工作 - session 在 bindSession()
和 unbindSession()
调用之间绑定(bind)到我的线程,我不必创建事务来实现这一目标。
关于java - 为后台线程创建 JPA session ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23732675/