java – 为后台线程创建JPA会话

我们通过JPA和Spring使用Hibernate来管理Web应用程序中的对象持久性.我们使用open-session-in-view模式为响应http请求的线程创建会话.我们还使用了一些不产生视图的线程 – 它们只是不时醒来完成工作.这会产生问题,因为认情况下它们没有打开会话,所以它们会产生异常

org.hibernate.SessionException: Session is closed! 

要么

 Could not initialize proxy - no Session

我们发现,如果每个后台线程在使用@Transactional注释的方法调用其逻辑,则没有这种类型的异常,因为@Transactional确保线程在事务内部时具有会话.

解决了一段时间的问题,但我不认为这是一个很好的解决方案 – 使长时间运行的方法事务导致问题,因为在提交事务之前,其他线程无法看到数据库中所做的更改.

我创建了一个java-pseudocode示例来更好地说明我的问题:

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中有会话,并且它将无法访问数据库.我也无法注释elementCanBeProcessed,因为它是这个类中的私有方法,我必须将它移动到另一个类,以便Spring代理可以工作.

是否可以将会话绑定到线程而不使整个方法具有事务性?我应该如何管理像那样的后台线程中的会话和事务?

最佳答案
我不知道任何针对此的Spring-ready解决方案.所以,我认为你需要实现一个类似于OpenEntityManagerInViewInterceptor类.

基本上,当你的线程启动时,你需要使用TransactionSynchronizationManager来绑定资源()一个EntityManagerHolder的实例,当线程完成时你需要使用unbindResource().

OpenEntityManagerInViewInterceptor的核心部分是:

    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);
        }
    }

如果您实施了,请在此处发布代码作为答案.

相关文章

这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
今天小编给大家分享的是一文解析spring中事务的传播机制,相...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...