【问题标题】:Should I close JNDI-obtained data source?我应该关闭 JNDI 获得的数据源吗?
【发布时间】:2011-07-21 10:06:25
【问题描述】:

更新:显然,从 7.0.11 开始,Tomcat 会为您关闭 DataSource,因此它在 webapp 的 contextDestroyed 中不可用。见:https://issues.apache.org/bugzilla/show_bug.cgi?id=25060

嗨,

我使用的是 Spring 3.0 和 Java 1.6。

如果我以这种方式获取数据源:

<bean id="dataSource" class="my.data.Source" destroy-method="close">
    <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="url" value="jdbc:oracle:thin:@localhost:1521:home"/>
    <property name="username" value="user"/>
    <property name="password" value="pw"/>
</bean>

那么当bean被销毁时,数据源就关闭了。

如果我得到这样的数据源:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/db" />

那么我是否必须在我的 contextDestroyed 侦听器中显式关闭数据源?

谢谢,

保罗

【问题讨论】:

    标签: spring tomcat7 datasource jndi spring-jdbc


    【解决方案1】:

    我不同意。我会在您的 web.xml 中添加一个侦听器并实现 contextDestroyed() 方法。当 Web 应用程序被销毁或取消部署时,您的 Web 容器/应用程序服务器将调用此方法。在 contextDestroyed() 中,我将关闭数据源。

    在 web.xml 中

    <listener>
       <listener-class>util.myApplicationWatcher</listener-class>
    </listener>
    

    代码:

    package util;
    
    public class myApplicationWatcher implementes ServletContextListener
    {
      public void contextInitialized(ServletContextEvent cs)
      {
          // This web application is getting started
    
          // Initialize connection pool here by running a query
          JdbcTemplate jt = new JdbcTemplate(Dao.getDataSource() );
          jt.queryForInt("Select count(col1) from some_table");
      }
    
      public void contextDestroyed(ServeletContextEvent ce)
      {
          // This web application is getting undeployed or destroyed 
    
          // close the connection pool
          Dao.closeDataSource();
      }
    }
    
    public class Dao
    {
      private static DataSource ds;
      private static bDataSourceInitialized=false;
      private static void initializeDataSource() throws Exception
      {
        InitialContext initial = new InitialContext();
    
        ds = (DataSource) initial.lookup(TOMCAT_JNDI_NAME);
    
        if (ds.getConnection() == null)
        {
          throw new RuntimeException("I failed to find the TOMCAT_JNDI_NAME");
        }
    
        bDataSourceInitialized=true;
      }
    
      public static void closeDataSource() throws Exception
      {
        // Cast my DataSource class to a c3po connection pool class
        // since c3po is what I use in my context.xml
        ComboPooledDataSource cs = (ComboPooledDatasource) ds;
    
        // close this connection pool
        cs.close();
      }
    
      public static DataSource getDataSource() throws Exception
      {
        if (bDataSourceInitialized==false)
        {
          initializeDataSource();
        }
    
        return(ds);
      }
    }
    

    【讨论】:

    • 事实证明这是正确的答案。我将问题发布到 Tomcat 邮件列表,responses 之一说因为 EE 规范说 JNDI 资源是在查找它们时创建的(因为我认为 java:comp 资源不在组件之间共享) webapp 应该在 contextDestroyed 中处理它。
    • 看起来 Tomcat 7 会为您处理数据源:issues.apache.org/bugzilla/show_bug.cgi?id=25060
    【解决方案2】:

    没有。这里的DataSource 由远程JNDI 容器管理,而管理DataSource 的生命周期是该容器的工作。 Spring 只是使用它,它不管理它。

    即使您想这样做,也做不到 - DataSource 没有 close() 方法或类似的方法。

    【讨论】:

    • 我将 DataSource 转换为底层类(例如 BasicDataSource)并调用该类的 close 方法。这是一件坏事还是没有必要?我应该做些什么来清理 contextDestroyed 中的数据访问?
    【解决方案3】:

    当您通过 JNDI 查找获取数据源时,它是一个共享资源 - 在您的容器中配置。它由容器而不是应用程序管理,因此不需要(没有办法)关闭它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-07
      • 2012-11-28
      • 1970-01-01
      • 2013-08-05
      • 2011-09-01
      • 2023-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多