Topic: 关于Tomcat的Connection管理问题

  Print this page

1.关于Tomcat的Connection管理问题 Copy to clipboard
Posted by: cxp108
Posted on: 2006-09-11 10:52

Tomcat 5.5
Red Hat Linux 9.0
PostgreSQL 8.1

使用以下方式获得连接

DataSource dr = (DataSource)context.lookup("jdbc/......");
Connection connection = ds.getConnection();

代码一开始运行正常,但经过多次运行后,出现以下情况

1. ds.getConnection()被完全阻塞了,不返回
2. 不会出现任何异常
3. 以上现象持续,直至重启Tomcat为止

采取以下手段都无法解决问题:

1. 手动关闭掉所有ResultSet , Statement , Connection
2. 不关闭所有ResultSet, Statement,Connection
3. 关闭ResultSet,Statement, 但不关闭Connection
4. 清空所有指向Connection 的引用

我分析一下以后觉得应该是Tomcat内部的ConnectionPool机制引起的,但详细原理并不清楚。

请问,该问题如何解决?

2.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: lisliefor
Posted on: 2006-09-12 09:02

Tomcat 5.5
Windows XP
SQL Server 2000

ds是DateSource的一个对象么?
原因我看不出来,不过,我可以将我们常用的连接池配置列出来,也许LZ能够找到一些灵感:

WEB-INF/tld/web.xml

3.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: lisliefor
Posted on: 2006-09-12 09:09

停电了!
.....

4.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: lisliefor
Posted on: 2006-09-12 09:15

<!-- Database proxool -->
  <servlet>
    <servlet-name>ServletConfigurator</servlet-name>
    <servlet-class>
      org.logicalcobwebs.proxool.configuration.ServletConfigurator
    </servlet-class>
    <init-param>
      <param-name>xmlFile</param-name>
      <param-value>
        WEB-INF/config/sqlserver_proxool.xml
      </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

写了一个配置文件,WEB-INF/config/sqlserver_proxool.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- the proxool configuration can be embedded within your own application's.
  Anything outside the "proxool" tag is ignored. -->
  
<something-else-entirely>
  <proxool>
    <alias>att</alias>
    <driver-url>
      jdbc:microsoft:sqlserver://localhost:1433;Databasename=att
    </driver-url>
    <driver-class>com.microsoft.jdbc.sqlserver.SQLServerDriver</driver-class>
    <driver-properties>
      <property name="user" value="sa" />
      <property name="password" value="sa" />
    </driver-properties>
    <maximum-connection-count>100</maximum-connection-count>
    <house-keeping-test-sql>
      select CURRENT_DATE
    </house-keeping-test-sql>
  </proxool>
</something-else-entirely>

注:连接池驱动(proxool-0.8.3.jar),如果需要,把你邮箱贴出来吧!

后面写的就是一个工具类了!

5.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: lisliefor
Posted on: 2006-09-12 09:18

/********************************************************************************
模块名    : 数据库管理器
文件名    : DatabaseManager.java
相关文件    :
文件实现功能  : 与数据库建立连接、断开连接、执行查询和更新操作
作者    : William@Passion Software
版本    : 1.1
--------------------------------------------------------------------------------
备注    : <灵活性不够>
--------------------------------------------------------------------------------
修改记录    :
日 期 版本 修改人 修改内容
31/07/2006 1.1 <William> <proxool连接池>
*******************************************************************************/

package com.passionsoft.util;

import java.sql.BatchUpdateException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DatabaseManager {

  private static final Log logger = LogFactory.getLog(DatabaseManager.class);

  // 批处理
  private String[] str; // 批处理语句包

  private static int flag = 0; // 数组指针

  private int no = 0; // 语句数目

  public DatabaseManager() {
  }

  /**
   * 从连接池获得一个数据库连接
   *
   * @return Connection
   *
   */
  public Connection getConnection() {

    Connection conn = null;

    try {
      Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
      conn = DriverManager.getConnection("proxool.att");
    } catch (ClassNotFoundException e) {
      // 在classpath中未找到合适的驱动
      logger.error(e.getMessage());
    } catch (SQLException e) {
      // 获取连接失败
      logger.error(e.getMessage());
    }

    if (conn != null) {
      if (logger.isDebugEnabled()) {
        logger.debug("Get a Connection from Connection Pool");
      }
      // System.out.println("Get a Connection from Connection Pool");
    }

    return conn;// 返回该Connection
  }

  /**
   * 传入执行查询的语句,返回结果集
   *
   * @param Connection
   * conn
   * @param String
   * sql
   * @return ResultSet
   */
  public ResultSet executeQuery(Connection conn, String sql) {

    Statement stmt = null;// 声明Statement stmt
    ResultSet rs = null;// 声明ResultSet rs

    if (conn != null) {
      // Connection 不为null,执行查询

      // 若debug模式开启,则输出debug 信息
      if (logger.isDebugEnabled()) {
        logger.debug(sql);
      }

      try {
        stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
            ResultSet.CONCUR_READ_ONLY);// 通过Connection创建一个Statemet
        rs = stmt.executeQuery(sql);// 执行查询语句,
      } catch (SQLException sqlex) {
        logger.error(sqlex.getMessage());
        return null;
      }
      return rs;
    } else {
      // Connection 为null,输出debug信息,返回null
      if (logger.isDebugEnabled()) {
        logger.debug("Connection is null");
      }
      return null;
    }
  }

  /**
   * 传入执行数据更新的语句,返回更新结果,成功执行为真
   *
   * @param Connection
   * conn
   * @param String
   * sql
   * @return boolean
   */
  public boolean executeUpdate(Connection conn, String sql) {

    boolean status = false;// 执行结果,默认为false

    Statement stmt = null;// 声明Statement stmt

    if (conn != null) {
      // Connection 不为null,执行更新

      // 若debug模式开启,则输出debug 信息
      if (logger.isDebugEnabled()) {
        logger.debug(sql);
      }

      try {
        stmt = conn.createStatement();// 通过Connection创建一个Statemet
        int count = stmt.executeUpdate(sql);// 执行更新数据操作,返回影响的行数

        // 根据count值,判断执行的成功或失败
        if (count > 0)
          status = true;
      } catch (SQLException sqlex) {
        logger.error(sqlex.getMessage());
      }
    } else {
      // Connection 为null,输出debug信息,返回false
      if (logger.isDebugEnabled()) {
        logger.debug("Connection is null");
      }
    }
    return status;

  }

  /**
   * 数据库语句批处理操作
   * @param str[]
   * 批处理语句包
   * @param conn
   */
  public boolean executeUpdateBatch(Connection conn, String[] str) {
    
    boolean status = false;    //执行结果
    
    Statement stmt = null;
    
    if(conn != null){
      
      try{
        // 当全部批处理都正确时,才执行数据提交执行;否则所有语句都不被执行
        conn.setAutoCommit(false);
        
        stmt = conn.createStatement();
        int[] rows;
        
        //添加批处理操作
        for(int i=0;i<str.length;i++)
          stmt.addBatch(" " + i +" " + str[i]);
        
        rows = stmt.executeBatch();
        
        //提交事务
        conn.commit();
        
        if(rows.length == str.length)
          status = true;
        
      }catch(BatchUpdateException bue){
        int[] success_rows;
        success_rows = bue.getUpdateCounts();
        System.err.println("Success Counts: " + success_rows);
      }catch(SQLException e){
        e.printStackTrace();
      }
    }
    
    return status;
  }

  /**
   * 批处理操作的辅助方法——将sql语句添加进处理批次中
   *
   * @param sql
   * 处理语句
   * @return
   */
  public void addSql(String sql) {
    str[flag] = sql;
    flag++;

    // 防止数组越界
    if (flag >= no)
      flag = 0;
  }

  /**
   * 批处理操作的辅助方法——设置批处理语句数目
   *
   * @param i
   * 处理语句数目
   */
  public void setBatch(int i) {
    str = new String[i];
    no = i;
  }

  /**
   * 批处理操作的辅助方法——获取处理语句包
   *
   * @return
   */
  public String[] getBatch() {

    flag = 0; // 获取处理语句包后,将指针拨回
    return str;
  }

  /**
   * 释放从连接池取得的连接
   *
   * @param Connection
   * conn
   */
  public void releaseConnection(Connection conn) {

    // 释放连接
    if (conn != null) {
      try {
        conn.close();
        if (logger.isDebugEnabled()) {
          logger.debug("Released a Connection to Connection Pool");
        }
        // System.out.println("Released a Connection to Connection
        // Pool");
      } catch (SQLException sqlex) {
        logger.error(sqlex.getMessage());
      } finally {
        conn = null;
      }
    }
  }
}

注:william是我们团队的老大,这里面只有相关批处理操作是我写的,还没有经过测试哦。 Smile
Log对象是用的appach的一个调试工具类

6.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: lisliefor
Posted on: 2006-09-12 09:24

覆写了executeUpdate、executeQuery方法,很多琐碎的东西都隐藏了,算一个小小的变通吧!
至少,数据库操作的方法,变得很精简,寥寥几行...... Smile
我们都是还没出去的大学生,自然没有保护意识,反正都是从网上搂别人的!
Big Smile

7.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: cxp108
Posted on: 2006-09-12 09:30

谢谢了

其实我用的方式就是网络上流传最简单的那种
1. 在server.xml中注册一个数据库连接
2. 在web.xml这中声明这个连接
3. 然后在servlet中使用这个连接

仅仅是让Tomcat去管理连接而已,我想问的是如果让Tomcat管理数据库连接,那么我们在使用完数据库连接后要手动进行什么处理么?

你们自己实现的连接池么?

8.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: lisliefor
Posted on: 2006-09-13 13:09

每个对数据库操作的方法,finally里,都调用 releaseConnection()方法,释放连接!
连接池参照别人的,不过改了一部分!
虽然,看上去比较繁琐,但是,这些繁琐的事情都留给了程序员!
很多实现都隐藏了,所以在使用的时候,相对比较方便!

9.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: wsfx
Posted on: 2006-09-14 16:35

我估计LZ是用了connection之后没有手工释放,导致连接一直被占用,当数据库连接到达一定数量之后,出现阻塞.记得用完之后应马上connnection.close()

10.Re:关于Tomcat的Connection管理问题 [Re: cxp108] Copy to clipboard
Posted by: cxp108
Posted on: 2006-09-15 08:39

我曾经尝试关闭所有的connection、Statement和ResultSet,并将它们的Reference指成null,但是都起不到任何作用。


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923