2012-11-23 17 views
5

po opracowaniu kilku aplikacji internetowych, które wszystkie miały podobną konfigurację ze sprężyną, hibernacją i c3p0 jako connectionpool, chciałem zbadać problem, który zauważyłem za każdym razem: Connectionpool utrzymuje połączenia, dopóki nie zamkniesz tomcat (lub serwera aplikacji).Jak zamknąć pulę połączeń po rozładowaniu kontekstu?

Dziś tworzę projekt najbardziej podstawowe mogłem z tych czterech zależności:

org.springframework:spring-web 
org.springframework:spring-orm 
org.hibernate:hibernate-core 
c3p0:c3p0 

(plus odpowiedni sterownik JDBC).

Mój web.xml tworzy tylko ContextLoaderListener, który konfiguruje kontekst aplikacji.

<context-param> 
    <param-name>contextConfigLocation</param-name> 
    <param-value> 
     /WEB-INF/applicationContext.xml 
    </param-value> 
</context-param> 

<listener> 
    <listener-class> 
     org.springframework.web.context.ContextLoaderListener 
    </listener-class> 
</listener> 

kontekst aplikacji składa się z dwóch ziaren - źródła danych i sesja fabryczne:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource" /> 
</bean> 

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 
    <property name="driverClass"> 
     <value>org.postgresql.Driver</value> 
    </property> 
    <property name="jdbcUrl"> 
     <value>jdbc:postgresql://localhost/mydb</value> 
    </property> 
    <property name="user"> 
     <value>usr</value> 
    </property> 
    <property name="password"> 
     <value>pwd</value> 
    </property> 
</bean> 

Kiedy uruchomić webapp i albo zajrzeć do MBean'ami JConsole lub sprawdź mój DBMS dla otwartych połączeń Zauważyłem trzy początkowe połączenia wykonane przez c3p0.

PROBLEM: Kiedy mówię Tomcat, aby zatrzymać webapp, nadal pozostają!

Utworzono inny obiekt ServContContextListener, który ma tylko metodę contextDestroyed zaimplementowaną i programowo wyłącza sessionFactory (a także wyrejestrowuje sterowniki JDBC, które również nie są wykonywane automatycznie). Kod:

@Override 
public void contextDestroyed(ServletContextEvent sce) { 

    ... 
    sessionFactory().close(); 

    // deregister sql driver(s) 
    Enumeration<Driver> drivers = DriverManager.getDrivers(); 
    while (drivers.hasMoreElements()) { 
     Driver driver = drivers.nextElement(); 
     try { 
      DriverManager.deregisterDriver(driver); 
      log.info("deregistering jdbc driver: " + driver); 
     } catch (SQLException e) { 
      log.error("error deregistering jdbc driver: " + driver, e); 
     } 
    } 
} 

Ale czy to naprawdę jest? Czy nie ma wbudowanego mechanizmu, którego nie jestem świadomy?

Odpowiedz

12

Czy próbowałeś podać metodę destroy?

<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
+0

Nie ma nic tak cennego jak doświadczenie ... zadziałało! Dziękuję (ale co z wyrejestrowaniem sterownika jdbc?) – realsim

+1

Wyrejestrowanie sterowników po prostu usuwa je z wewnętrznej statycznej listy 'DriverManager'. Gdy następnym razem pula połączeń chce zdobyć nowy zasób, prosi o podanie "DriverManager". Ale jeśli połączenie zostało już nabyte i pozostaje w puli, nic nie przeszkadza mu w kontynuowaniu pracy. BTW, powoduje to również wycieki pamięci klasy Loader, ponieważ wątki puli połączeń nie pozwalają na niszczenie klas. Zaznacz pytanie jako rozwiązane, jeśli uważasz, że nie masz więcej pytań. –

+0

@realsim: nie zapomnij przyjąć tej odpowiedzi! –

Powiązane problemy