0

所以我有一个每分钟查询数据库的 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 的方式编写它...

4

3 回答 3

2

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

  1. 验证容器是否正常停止。
  2. destroy()方法内部没有异常
  3. 尝试在方法请求时记录一些字符串或在调试器中设置断点。

此外,如果您使用的是旧版本的 Tomcat,请注意此错误

于 2012-04-30T17:35:16.173 回答
1

如果您使用的是 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
    }
  }
于 2012-04-30T17:59:12.070 回答
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 之前)的特殊东西。

于 2012-04-30T17:27:03.667 回答