首页 文章

每次会话的JPA 2(Hibernate)持久化上下文 - 关闭连接

提问于
浏览
0

我正在尝试使用JBoss 4.3.0和Hibernate 4.3.5在有状态的专有Web框架上实现实体管理器每会话模式 . 简而言之,目标是:

  • 第一个HTTP请求从数据库加载具有延迟加载属性的实体A.

  • 在第二个请求中,实体A的延迟加载属性可以在没有例如的情况下访问 . 创建一个新的EntityManager并调用例如entityManager.merge(entityA) .

Entitymanager-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,但还没有设法将它弯曲到我的需要 .

1 回答

  • 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 - 我们手动传递连接 .

    我发布这个以防万一有人遇到类似的问题 . 这个解决方案非常不正统,我希望以后用更好的方法替换它 .

相关问题