我尝试使用JBoss 4.3.0和Hibernate 4.3.5在有状态的专有Web框架上实现每个会话的实体管理器模式。简而言之,目标是:
Entityman-per-conversation似乎是完美的选择。这是我的尝试:
public class EntityManagerHolder {
private static ThreadLocal<EntityManager> entityManager = new ThreadLocal<EntityManager>();
private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myPersistence");
private static ConnectionProvider connectionProvider = new MyConnectionProvider();
public static synchronized EntityManager getEntityManager() {
createEntityManagerIfNeeded();
return entityManager.get();
}
public static synchronized void createEntityManagerIfNeeded() {
if (entityManager.get() == null) {
// Start the conversation
EntityManager newEntityManager = entityManagerFactory.createEntityManager();
entityManager.set(newEntityManager);
newEntityManager.getTransaction().begin();
} else {
// Entitymanager is alive but may have lost its connection
EntityManager existingEntityManager = entityManager.get();
SessionImpl session = existingEntityManager.unwrap(SessionImpl.class);
try {
if (session.connection() == null || session.connection().isClosed()) {
session.reconnect(connectionProvider.getConnection());
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
的persistence.xml:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="myEntityManagerFactory">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- Scan for annotated classes and Hibernate mapping XML files from this JAR -->
<property name="hibernate.archive.autodetection" value="class, hbm" />
<!-- Database connection settings: Use framework connections for database connectivity -->
<property name="hibernate.connection.provider_class" value="foo.bar.MyConnectionProvider"/>
</properties>
</persistence-unit>
</persistence>
当新的HTTP请求通过框架到达时,我调用EntityManagerHolder.createEntityManagerIfNeeded()。在第二个HTTP请求中,EntityManager的JDBC连接已关闭,尝试通过session.reconnect()恢复它会导致异常:
java.lang.IllegalStateException: cannot manually reconnect unless Connection was originally supplied
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.manualReconnect(LogicalConnectionImpl.java:296)
org.hibernate.internal.SessionImpl.reconnect(SessionImpl.java:478)
我意识到我可能会以非常倒退的方式做事,但了解如何实施每个对话的实体管理员会很好。我已经找到了这种模式的基于过滤器的Hibernate-specific sample implementation,但还没有设法将其弯曲到我的需要。
答案 0 :(得分:0)
结果JBoss was closing the connections。禁止JBoss关闭JDBC连接可以解决问题。但是,我们希望避免长时间保持大量JDBC连接打开。
到目前为止,找到的最佳解决方案是恢复EntityManager的JDBC连接,前提是旧连接已关闭。我写了一个粗略的实现:
EntityManagerFactoryAdapter - 用于将EntityManager重新连接到新的JDBC连接
EntityManagerHolder - 每个线程保留一个EntityManager。
在每个HTTP请求开始时,我们调用EntityManagerHolder.initializeEntityManager(freshJDBCConnectionFromFramework)。当从服务器中删除状态时,我们调用EntityManagerHolder.closeEntityManager()。 Persistence.xml不再具有hibernate.connection.provider_class - 我们手动传入连接。
我发布此信息以防有人遇到类似问题。这个解决方案非常不正统,我希望以后用更好的解决方案替换它。