2013-03-08 24 views
8

Niedawno zacząłem używać hibernacji wraz z c3p0 jako ORM w mojej aplikacji. Jednak po zamknięciu fabryki sesji pula połączeń nie zamyka się! To jest jedno jedyne miejsce w mojej aplikacji, gdzie robię cokolwiek z sesją.Hibernate: zamknięcie fabryki sesji nie zamyka puli połączeń c3p0

StatelessSession session = null; 
    Transaction transaction = null; 


    try { 
     session = sessionFactory.openStatelessSession(); 
     transaction = session.beginTransaction(); 

     List<Thingy> list = session.getNamedQuery("getAvailableThingy").list(); 

     transaction.commit(); 
     return list; 

    } catch (Exception error) { 
     if (transaction != null) { 
      transaction.rollback(); 
     } 
     throw error; 
    } finally { 
     if (session != null) { 
      session.close(); 
     } 
    } 

To jest mój plik hibernate.cfg.xml konfiguracja

<?xml version='1.0' encoding='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC 
"-//Hibernate/Hibernate Configuration DTD//EN" 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 


<hibernate-configuration> 
    <session-factory> 
     <property name="hibernate.connection.driver_class">org.postgresql.Driver</property> 
     <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property> 
     <property name="javax.persistence.validation.mode">none</property> 
     <property name="hibernate.connection.release_mode">after_transaction</property> 

     <property name="hibernate.c3p0.minPoolSize">1</property> 
     <property name="hibernate.c3p0.maxPoolSize">2</property> 
     <property name="hibernate.c3p0.acquireIncrement">1</property> 
     <property name="hibernate.c3p0.initialPoolSize">1</property> 
     <property name="hibernate.c3p0.timeout">30</property> 
     <property name="hibernate.c3p0.maxIdleTimeExcessConnections">5</property> 
     <property name="hibernate.c3p0.idleConnectionTestPeriod">300</property> 
    </session-factory> 
</hibernate-configuration> 

Zauważ, że powodem, dla którego bardzo krótkim związku bezczynności to, że jego jedyny sposób znalazłem jeszcze, aby moje testy integracyjne przekazać. Bardzo często otwierają i zamykają fabrykę sesji, przez co zawsze kończą mi się połączenia. Ponieważ jesteśmy na początku projektu, w dłuższej perspektywie nie jest to bardzo trwała strategia.

"Ciekawą rzeczą, o której należy pamiętać, jest to, że pomimo ustawienia początkowej puli połączeń na jedną, c3p0 nadal próbuje otworzyć dwa połączenia na starcie. Domyślam się, że istnieje gdzieś ukryta sesja, która nie jest zamknięta (ale gdzie mnie pokonać).

Jak więc uzyskać tę irytującą pulę połączeń, aby się zamknąć?

Dodatkowe informacje: jak tworzyć i niszczyć moja fabryka sesja

import static com.google.common.base.Preconditions.*; 

import javax.inject.Inject; 
import javax.inject.Provider; 
import javax.inject.Singleton; 
import org.hibernate.SessionFactory; 
import org.hibernate.cfg.Configuration; 
import org.hibernate.service.ServiceRegistry; 
import org.hibernate.service.ServiceRegistryBuilder; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import com.google.inject.Provides; 


@Singleton 
public class PostgisConnection implements Provider<SessionFactory>, AutoCloseable { 
    private final Logger logger = LoggerFactory.getLogger(getClass()); 
    private final ConnectionInfo connectionInfo; 
    private SessionFactory sessionFactory = null; 

    @Inject 
    public PostgisConnection(ConnectionInfo connectionInfo) { 
     this.connectionInfo = connectionInfo; 
    } 

    public AutoCloseable open() { 
     checkState(sessionFactory == null, "Connections to postgis are already open"); 

     logger.info("Creating sessionFactory for connection to postgis: {}", connectionInfo.getJdbcUrl()); 
     sessionFactory = newPostgisSessionFactory(connectionInfo); 

     return this; 
    } 

    @Override 
    public void close() throws Exception { 
     try { 
      if (sessionFactory != null) { 
       logger.info("Closing sessionFactory for postgis: {}", connectionInfo.getJdbcUrl()); 
       sessionFactory.close(); 
       checkState(sessionFactory.isClosed(), "Session factory should be closed at this point"); 
      } 
     } catch (Exception error) { 
      logger.error("Error closing SessionFactory", error); 
     } 
    } 

    @Provides 
    public SessionFactory get() { 
     return sessionFactory; 
    } 

    public static SessionFactory newPostgisSessionFactory(ConnectionInfo connectionInfo) { 
     Configuration configuration = configurationWith(connectionInfo); 
     return configuration.buildSessionFactory(registryFrom(configuration)); 
    } 

    private static Configuration configurationWith(ConnectionInfo connectionInfo) { 
     Configuration configuration = new Configuration(); 
     setConnectionInfo(connectionInfo, configuration); 
     configuration.addURL(PostgisConnection.class.getResource("mapping.hbm.xml")); 
     configuration.configure(PostgisConnection.class.getResource("hibernate.cfg.xml")); 

     return configuration; 
    } 

    private static void setConnectionInfo(ConnectionInfo connectionInfo, Configuration configuration) { 
     configuration.setProperty("hibernate.connection.url", connectionInfo.getJdbcUrl()); 
     configuration.setProperty("hibernate.connection.username", connectionInfo.getUsername()); 
     configuration.setProperty("hibernate.connection.password", connectionInfo.getPassword()); 
    } 

    private static ServiceRegistry registryFrom(Configuration configuration) { 
     return new ServiceRegistryBuilder() 
       .applySettings(configuration.getProperties()) 
       .buildServiceRegistry(); 
    } 

} 
  • wersji hibernacji: 4.1.10.Final
  • C3P0 wersja: 0.9.1.2
+0

Dlaczego chcesz zamknąć pulę połączeń? Nie będzie można wybrać nowego połączenia, jeśli jest ono zamknięte. – dotvav

+0

SessionFactory zostaje zamknięty i uruchomiony ponownie między niektórymi testami integracji, aby uniknąć utrzymywania się stanu, który może mieć na nie wpływ. Zamykam też swój WebServer, zamykam połączenie Unix Socket, usuwam testową bazę danych ... wszystko naprawdę. Powinien być nieskazitelnie czysty po rozpoczęciu drugiego testu. Oczywiście w produkcji nie poświęcam czasu na zamykanie i ponowne uruchamianie tych rzeczy, co byłoby całkiem bezużyteczne. –

+0

dla każdego dokumentu w trybie hibernacji, SessionFactor.close() powinien zamknąć pulę: "Zniszcz tę SessionFactory i zwolnij wszystkie zasoby (pamięci podręczne, pule połączeń itp.)." [http://docs.jboss.org/hibernate/orm/4.1/javadocs/org/hibernate/SessionFactory.html] czy w dziennikach można zobaczyć, że twoja metoda close() jest wywoływana, kiedy oczekujesz? kilka pomysłów: 1) c3p0-0.9.1.2 jest trochę długi w zębie, spróbuj przejść do całkiem dojrzałego c3p0-0.9.2; 2) bądź świadomy, że c3p0 close() niekoniecznie jest natychmiastowe: c3p0 zarządza grupą wątków, które są przerywane i czyści rzeczy na bliskim, wybitne cxns muszą zostać zwrócone –

Odpowiedz

13

miałem ten sam problem i z powodzeniem wykorzystano obejście oferowane: in this bug report:

private void closeSessionFactory(SessionFactory factory) { 
    if(factory instanceof SessionFactoryImpl) { 
     SessionFactoryImpl sf = (SessionFactoryImpl)factory; 
     ConnectionProvider conn = sf.getConnectionProvider(); 
     if(conn instanceof C3P0ConnectionProvider) { 
     ((C3P0ConnectionProvider)conn).close(); 
     } 
    } 
    factory.close(); 
} 

Musisz odwołać się do słoika hibernacji-c3p0-4.x.x.

+0

Dzięki temu skończyło nam się trochę bardziej skomplikowana praca, która przyda się. –

0

miałem ten sam problem i skutecznie wykorzystał ehnanced (styczeń 2014) obejście oferowane in this bug report:

private static boolean closeSessionFactoryIfC3P0ConnectionProvider(SessionFactory factory) { 

    boolean done = false; 
    if(factory instanceof SessionFactoryImpl) { 
     SessionFactoryImpl sf = (SessionFactoryImpl)factory; 
     ConnectionProvider conn = sf.getConnectionProvider(); 
     if(conn instanceof C3P0ConnectionProvider) { 
      ((C3P0ConnectionProvider)conn).close(); 
      try { 
       Thread.sleep(2000); //Let give it time...it is enough...probably 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      done = true; 
     } 
     factory.close(); 
    } 
    return done; 

} 

Trzeba odwołać słoik hibernacji-c3p0-4.x.x.