即使我告诉它,Servlet destroy方法也没有关闭数据库连接

时间:2012-04-30 17:10:38

标签: java servlets jdbc

所以我有一个每分钟查询数据库的servlet,所以我想我将永远打开一个连接(好吧,直到webapp停止)。因此我在init()中打开一个连接并在destroy()中关闭它。事实是,如果我在tomcat中停止应用程序后查看数据库,则连接仍处于打开状态。发生了什么事?

这是我的代码:

public void init() throws ServletException
{
    try
    {
        // Prepare the DB connection
        DriverManager.registerDriver(new com.informix.jdbc.IfxDriver());
        informixConnection = DriverManager.getConnection(DBURL, DBUsername, DBPassword);
    }
    catch(SQLException e)
    {
        throw new UnavailableException("Error connecting to the database");
    }
}

public void destroy()
{
    try
    {
        informixConnection.close();     
    }
    catch(Exception e)
    {
    }
}

还会有一个实际执行查询的方法,以及一个doGet,以便用户可以获得最新的响应,但我还没有完成这些(虽然我已经测试过它们并且数据库连接有效)。


我不知道为什么这不起作用。我在destroy方法中添加了一些日志记录,以确认在应用程序关闭时它被调用,突然它开始工作了。怪异。

好的,现在去用非servlet方式编写它......

3 个答案:

答案 0 :(得分:2)

根据文档,只有在servlet中的所有线程都退出或发生超时后才会调用destroy()。所以理论上应该始终调用destroy,除非容器没有优雅地停止。

  1. 验证容器是否正常停止。
  2. destroy()方法
  3. 中没有例外
  4. 尝试在方法的乞讨处记录一些字符串或设置一个断点 调试器。
  5. 此外,如果您使用旧版本的Tomcat,请注意此bug

答案 1 :(得分:0)

init()和destroy()方法与Servlet的生命周期相关联。

典型servlet的生命周期是容器中应用程序的生命周期。

在正常情况下,对于通用servlet,应用程序将部署到容器,并启动应用程序。此时,servlet不存在。

一旦请求被定向到映射到Servlet的URL,容器就会检查它是否还没有启动该Servlet的实例。如果没有,它将调用Servlet上的init()方法,然后开始向它发送路由请求。通常,应用程序中一次只有一个Servlet实例。

作为替代方案,可以在web.xml中使用load-on-startup参数配置Servlet,如果存在,则在应用程序启动期间初始化Servlet,而不是等待初始化Servlet的请求。

稍后,当容器关闭或应用程序取消部署时,容器将在应用程序生命周期内初始化的任何Servlet上调用destroy()方法。

因此,总而言之,如果您希望将init()和destroy()方法绑定到各个请求,那么您的期望就会错位。为此,你会看到一个ServletRequestListener(Servlet 3.0),或使用Servlet过滤器(3.0之前的版本)的特殊内容。

答案 2 :(得分:0)

如果您正在使用Tomcat,则可以创建资源

  <Resource name="jdbc/AutoOracle"
        auth="Container"
        type="javax.sql.DataSource"
        driverClassName="oracle.jdbc.driver.OracleDriver"
        username="usrname"
        password="pswd"
        url="jdbc:oracle:thin:@yourdb:1521:yourdb"
        maxActive="1500"
        maxIdle="30"
        maxWait="5000"
        removeAbandoned="true"
        removeAbandonedTimeout="900"
        timeBetweenEvictionRunsMillis="300000"
        minEvictableIdleTimeMillis="1800000"
        testOnBorrow="true"
        testWhileIdle="true"
        validationQuery="select 'test' from Dual"
        validationQueryTimeout="3"
        />

在servlet中创建一个Context

Context dataSourceContext = new InitialContext();

然后使用上下文在需要连接的方法内创建数据库连接。

  Connection conn = null;
  try{
    DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/AutoOracle");
    conn = ds.getConnection();
    if(conn == null){
      log.error("Connection is null");
    }else{
      // do some work
    }
  }catch(Exception e){
    // handle exceptions
  }finally{
    try{
      conn.close();
    }catch(Exception e){
      // handle exception
    }
  }