加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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

发布时间:2020-12-15 01:38:52 所属栏目:大数据 来源:网络整理
导读:我们通过JPA和Spring使用Hibernate来管理Web应用程序中的对象持久性.我们使用open-session-in-view模式为响应http请求的线程创建会话.我们还使用了一些不产生视图的线程 它们只是不时醒来完成工作.这会产生问题,因为默认情况下它们没有打开会话,所以它们会产

我们通过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);
        }
    }

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读