我們使用Hibernate(使用JPA)和Hibernate Envers來保存對象的歷史記錄。 Web應用程序運行很多線程,其中一些是通過其他應用程序的RMI方法調用創建的,其中一些是由應用程序本身創建的,其中一些創建來處理http請求(它們會生成視圖)。Spring + Hibernate + Envers +多線程 - 會話關閉
我們還使用打開會話視圖模式來管理會話,所以我們的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的訪問,所有的人都EntityManagers由Spring注入。
@PersistenceContext
protected EntityManager em;
@PersistenceUnit
protected EntityManagerFactory emf;
在我們決定使用Hibernate Envers之前,一切都運行良好。當任何不是視圖生成線程的線程運行代碼以獲取對象的舊版本時,將拋出異常。在線程 「計劃」 org.hibernate.SessionException
@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;
}
例外: 會話關閉!在 org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:129) 在 org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1776) 在 org.hibernate.envers.tools.query。 QueryBuilder.toQuery(QueryBuilder.java:226) 在 org.hibernate.envers.query.impl.AbstractAuditQuery.buildQuery(AbstractAuditQuery.java:92) 在 org.hibernate.envers.query.impl.EntitiesAtRevisionQuery.list( EntitiesAtRevisionQuery.java:108) 在 org.hibernate.envers.query.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)?