2014-06-05 2 views
0

Я пытаюсь реализовать шаблон entitymanager для разговора на проприетарной веб-платформе с сохранением состояния с помощью JBoss 4.3.0 и Hibernate 4.3.5. Короче говоря, цель:Контекст сохранения JPA 2 (Hibernate) для разговора - закрытое соединение

  • Первого HTTP запрос загружает объект А с отложенной загрузкой объектами из базы данных
  • Во втором запросе, свойство отложенной загрузки сущностей А доступны без, например, создание нового 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, соединение JDBC из EntityManager закрыло и попытка оживить его с помощью 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 для разговора. Я нашел на основе фильтра Hibernate-specific sample implementation этого шаблона, но до сих пор не смог его свернуть.

ответ

0

Оказывается JBoss was closing the connections. Отключение JBoss от закрытия соединений JDBC решило бы проблему. Однако мы хотели избежать длительного открытия большого количества подключений JDBC.

Лучшее решение, найденное до сих пор, заключается в том, чтобы оживить соединение JDBC EntityManager при условии, что старое соединение закрыто. Я написал грубую реализацию:

EntityManagerFactoryAdapter - Используется для повторного подключения к EntityManager к новому соединению JDBC

EntityManagerHolder - Сохраняет один EntityManager для каждого потока.

В начале каждого HTTP-запроса мы вызываем EntityManagerHolder.initializeEntityManager (freshJDBCConnectionFromFramework). Когда состояние удаляется с сервера, мы вызываем EntityManagerHolder.closeEntityManager(). Persistence.xml больше не имеет hibernate.connection.provider_class - мы передаем соединения вручную.

Я отправляю это на случай, если кто-то столкнется с аналогичной проблемой. Это решение очень неортодоксально, я надеюсь заменить его на более поздний.

Смежные вопросы