2014-06-05 22 views
0

我試圖在JBoss 4.3.0和Hibernate 4.3.5的狀態專有Web框架上實現entitymanager-per-conversation模式。總之,我們的目標是:每個對話JPA 2(Hibernate)持久化上下文 - 關閉連接

  • 從數據庫
  • 在第二請求延遲加載屬性第一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) 

我意識到我可能做的事情非常落後方式,但很好理解應該如何實施entitymanager-per-conversation。我發現了這種模式的基於過濾器的Hibernate-specific sample implementation,但還沒有設法使其符合我的需求。

回答

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 - 我們手動傳遞連接。

我發佈這只是以防萬一有人遇到類似的問題。這個解決方案非常非正統,我希望以後用更好的替換它。