当前位置: 首页 > 知识库问答 >
问题:

Spring Hibernate Envers多线程-会话已关闭

终育
2023-03-14

我们使用Hibernate(JPA)和Hibernate Envers来保存对象的历史。Web应用程序运行许多线程,其中一些是通过从其他应用程序调用RMI方法创建的,其中一些是由应用程序本身创建的,其中一些是为了处理超文本传输协议请求而创建的(它们生成视图)。

我们还使用视图中的开放会话模式来管理会话,因此我们的web。xml包含:

<filter>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>openEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

数据库是使用DAO访问的,它们都有由Spring注入的实体管理器。

@PersistenceContext
protected EntityManager em;

@PersistenceUnit
protected EntityManagerFactory emf;

在我们决定使用Hibernate Envers之前,一切都运行得很好。当不是视图生成线程的任何线程运行代码以获取对象的旧版本时,将引发异常。

@Override
public O loadByRevision(Long revision, Long id) {
    @SuppressWarnings("unchecked")
    O object = (O) AuditReaderFactory.get(em).createQuery().forEntitiesAtRevision(getBaseClass(), revision.intValue())
            .add(AuditEntity.id().eq(id)).getSingleResult();
    return object;
}

线程“调度程序”组织中出现异常。冬眠SessionException:会话已关闭!在org。冬眠内部的AbstractSessionImpl。org上的errorIfClosed(AbstractSessionImpl.java:129)。冬眠内部的SessionImpl。在org上创建查询(SessionImpl.java:1776)。冬眠恩弗斯。工具。查询QueryBuilder。toQuery(QueryBuilder.java:226)位于org。冬眠恩弗斯。查询impl。AbstractAuditQuery。org上的buildQuery(AbstractAuditQuery.java:92)。冬眠恩弗斯。查询impl。EntitiesAtRevisionQuery。组织上的列表(EntitiesAtRevisionQuery.java:108)。冬眠恩弗斯。查询impl。AbstractAuditQuery。getSingleResult(AbstractAuditQuery.java:110)(…)

当上面的代码由视图生成线程运行时,它工作正常。此外,DAO中的非envers代码对于每个线程都可以正常工作。例如,下面的代码片段

@Override
public O load(Long id) {
    final O find = em.find(getBaseClass(), id);
    return find;
}

可以运行的RMI线程没有问题。

为什么非视图线程可以无例外地调用实体管理器上的方法,但不能对该实体管理器使用Envers的AuditReaderFactory?我想也许调用实体管理器上的方法会创建一个临时会话,但在使用Envers时不会发生这种情况,是真的吗?

解决该问题的最佳方法是什么(以便可以从每个线程使用AuditReaderFactory)?

共有1个答案

闾丘选
2023-03-14

我们没有找到为什么在非ui线程中,对EntityManagerFactory的方法调用有效,但对AuditReaderFactory的方法调用无效。无论如何,我们找到了一种解决方法。

解决方案是用@Transactional注释方法。如果在调用AuditReaderFactory之前调用链中的任何方法被标记为@Transactional,则在非ui线程中没有SessionExcture

结果证明,仅使loadByRevision具有事务性是不够的。如果该方法返回的对象包含延迟加载的持久性包,则在loadByRevision方法范围之外访问这些包会导致LazyInitializationException(没有会话)。

最后的解决方案是确保如果任何线程想要从数据库加载一些数据,所有加载(获取对象和访问延迟加载的集合)都将在一个方法内完成,该方法用@Transactional注释。

 类似资料:
  • 问题内容: 当我按如下方式调用session.begin事务方法时: 然后我得到以下异常消息 造成此错误的原因是什么? 问题答案: 更新: 我想调用并不能保证该会话实际上是打开的。第一次,您应该使用 代替。该建议实际上与您找到的页面一致。 之前: 根据到目前为止的可用信息,我们可以得出结论,错误的原因是会话未打开;-)

  • 我有两个运行在不同机器上的ActiveMQ Artemis代理,组成一个简单的集群。我正在使用一个Java应用程序(非常基本)来生成和使用消息,以分析集群的行为。Java代码如下所示: 同时在处使用断点调试上述应用程序。如果我停止我的主代理,那么我会看到从代理接管,所有的消息都像预期的那样被移动到从代理。但是,此时,如果我继续使用我的应用程序,它将抛出,而不是在从代理中使用消息。当我再次启动主代理

  • 问题内容: 我在hibernate和延迟加载方面遇到问题。 背景:我有一个Spring MVC Web应用程序,我将Hibernate用于持久层。我正在使用OpenSessionInViewFilter使我能够在视图层中延迟加载实体。我正在扩展HibernateDaoSupport类,并使用HibernateTemplate保存/加载对象。一切都进行得很好。直至现在。 问题:我有一个可以通过Web

  • 问题内容: 我知道会话不是线程安全的。我的第一个问题:将实体传递给另一个线程,对它做一些工作,然后将其传递回原始线程并进行更新,是否安全? 我的第二个问题:在一个线程中创建一个实体并将其保存在另一个线程中是否安全? 编辑 我忘了提到实体是为快速加载而专门配置的 问题答案: 否。该实体已附加到会话中,并包含链接到该会话的代理(以延迟自身加载)。因此,这样做将使用多个线程中的会话。由于会话不是线程安全

  • 我使用cassandra作为web应用程序(java)的后端,每个用户都需要创建唯一的会话,或者使用下面url中的单个会话? 我在这个链接中阅读了会话信息。https://docs.datastax.com/en/drivers/java/2.0/com/datastax/driver/core/Session.html 它说会话实例是线程安全的。意味着一次一个线程可以使用这个实例。 还写到,每个

  • 我们如何优雅地关闭守护进程线程[ActiveMQ会话:ID:PC-63704-1472105244157-1:1:1]? spring-boot activeMQ设置如下所示 对于发送消息,我们只是简单地autowired JmsTemplate并发送消息出去: 对于接收(监听)消息,我们使用Spring DefaultMessageListenerContainer(DMLC) 我们还有其他的设