Tomcat 4.1.29是目前的最高稳定版本,下面介绍一下它的连接池配置Ҏ?br />1) q接池配|?Database Connection Pool (DBCP) Configurations)
DBCP使用的是Jakarta-Commons Database Connection Pool 要用连接池需要如下的lg即jar文g?br />Jakarta-Commons DBCP 1.1 对应commons-dbcp-1.1.jar?br />Jakarta-Commons Collections 2.0 对应commons-collections.jar?br />Jakarta-Commons Pool 1.1 对应commons-pool-1.1.jar?br />q三个jar文g要与你的JDBC驱动E序一h到【TOMCAT_HOME】\common\lib目录下以便让tomcat和你的web应用都能够找到?br />注:q三个jar文g是默认存在与【TOMCAT_HOME】\common\lib下的?br />需要注意的地方Q第三方的驱动程序或者其他类只能?.jar的Ş式放到Tomcat的common\lib目录?因ؓTomcat只把*.jar文g加到CLASSPATH中?br />不要把上诉三个文件放到WEB-INF/lib或者其他地方因样会引vh?br />
2) 通过配置Lq接池漏z?br />数据库连接池创徏和管理连接池中徏立好的数据库q接Q@环用这些连接以得到更好的效率。这h始终Z个用户保持一个连接和为用Lh频繁的徏立和销毁数据库q接要高效的多?br />q样有一个问题出CQ一个Web应用E序必须昄的释放ResultSetQStatement和Connection。如果在关闭q些资源的过E中p|导致这些资源永q不在可用,q就是所谓的q接池漏z。这个漏z最l会Dq接池中所有的q接不可用?br />通过配置Jakarta Common DBCP可以跟踪和恢复那些被遗弃的数据库q接?br />以下是一pd相关配置Q?br /> 通过配置DBCP数据源中的参数removeAbandoned来保证删除被遗弃的连接其可以被重新利用?br />为ResourceParams(见下文的数据源配|?标签d参数removeAbandoned
<parameter>
<name>removeAbandoned</name>
<value>true</value>
</parameter>
通过q样配置的以后当q接池中的有效连接接q用完时DBCP试图恢复和重用被遗弃的q接。这个参数的值默认是false?br /> 通过讄removeAbandonedTimeout来设|被遗弃的连接的时的时_卛_一个连接连接被遗弃的时间超q设|的旉旉么它会自动{换成可利用的q接?br /> <parameter>
<name>removeAbandonedTimeout</name>
<value>60</value>
</parameter>
默认的超时时间是300U?br /> 设|logAbandoned参数Q这个参数的用处我没能够理解它的意义所以提供原文供大家参考?br />The logAbandoned parameter can be set to true if you want DBCP to log a stack trace of the code which abandoned the dB connection resources?br /><parameter>
<name>logAbandoned</name>
<value>true</value>
</parameter>
q个参数默认为false?br />
3) 下面以MySQLZ演示Tomcat数据库连接池的配|?br /> MySQL的版本以及对应的JDBC驱动E序
MySQL 3.23.47, MySQL 3.23.47 using InnoDB, MySQL 4.0.1alpha对应的驱动ؓmm.mysql 2.0.14 (JDBC Driver)?br /> 在MySQL中创Z试的数据库Q表l构以及数据
mysql> create database javatest;
mysql> use javatest;
mysql> create table testdata (
-> id int not null auto_increment primary key,
-> foo varchar(25),
-> bar int);
mysql> insert into testdata values(null, 'hello', 12345);
Query OK, 1 row affected (0.00 sec)
mysql> select * from testdata;
+----+-------+-------+
| ID | FOO | BAR |
+----+-------+-------+
| 1 | hello | 12345 |
+----+-------+-------+
1 row in set (0.00 sec)
要注意的是登录的mysql用户要有创徏数据库的权限q有注意要设|密码我用的是root^_^?br /> 配|Tomcat的server.xml文g
配置【TOMCAT_HOME】\common\lib下的server.xml文gQ在</host>标签之前加入以下内容以添加JNDI数据源:
<Context path="/DBTest" docBase="DBTest"
debug="5" reloadable="true" crossContext="true">
<Logger className="org.apache.catalina.logger.FileLogger"
prefix="localhost_DBTest_log." suffix=".txt"
timestamp="true"/>
<Resource name="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/TestDB">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!-- Maximum number of dB connections in pool. Make sure you
configure your mysqld max_connections large enough to handle
all of your db connections. Set to 0 for no limit.
-->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<!-- Maximum number of idle dB connections to retain in pool.
Set to 0 for no limit.
-->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<!-- Maximum time to wait for a dB connection to become available
in ms, in this example 10 seconds. An Exception is thrown if
this timeout is exceeded. Set to -1 to wait indefinitely.
-->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<!-- MySQL dB username and password for dB connections -->
<parameter>
<name>username</name>
<value>javauser</value>
</parameter>
<parameter>
<name>password</name>
<value>javadude</value>
</parameter>
<!-- Class name for mm.mysql JDBC driver -->
<parameter>
<name>driverClassName</name>
<value>org.gjt.mm.mysql.Driver</value>
</parameter>
<!-- The JDBC connection url for connecting to your MySQL dB.
The autoReconnect=true argument to the url makes sure that the
mm.mysql JDBC Driver will automatically reconnect if mysqld closed the
connection. mysqld by default closes idle connections after 8 hours.
-->
<parameter>
<name>url</name> <value>jdbc:mysql://localhost:3306/javatest?autoReconnect=true</value>
</parameter>
</ResourceParams>
</Context>
配|Web应用E序的web.xml文g
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<description>MySQL Test App</description>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/TestDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
测试代?br />试代码包括一个JSP文g和一个JavacR代码如下:
- <html>
- <head>
- <title>DB Test</title>
- </head>
- <body>
- <%
- foo.DBTest tst = new foo.DBTest();
- tst.init();
- %>
- <h2>Results</h2>
- Foo <%= tst.getFoo() %><br>
- Bar <%= tst.getBar() %>
- </body>
- </html>
- package foo;
- import javax.naming.*;
- import javax.sql.*;
- import java.sql.*;
- public class DBTest {
- String foo = "Not Connected";
- int bar = -1;
-
- public void init() {
- try{
- Context ctx = new InitialContext();
- if(ctx == null )
- throw new Exception("Boom - No Context");
- DataSource ds =
- (DataSource)ctx.lookup(
- "java:comp/env/jdbc/TestDB");
- if (ds != null) {
- Connection conn = ds.getConnection();
- if(conn != null) {
- foo = "Got Connection "+conn.toString();
- Statement stmt = conn.createStatement();
- ResultSet rst =
- stmt.executeQuery(
- "select id, foo, bar from testdata");
- if(rst.next()) {
- foo=rst.getString(2);
- bar=rst.getInt(3);
- }
- conn.close();
- }
- }
- }catch(Exception e) {
- e.printStackTrace();
- }
- }
- public String getFoo() { return foo; }
- public int getBar() { return bar;}
- }
最后在Tomcat的webapps目录下徏立DBTest然后应用程序文件拷贝到q个目录下即可?br /> 重新启动Tomcat在浏览器上http://localhost:8080/DBTest/test.jsp卛_看到l果?br />Results
Foo hello
Bar 12345
4) 一些常见的问题
由于垃圾收集器的运行而导致连接超?br />Tomcat是运行在JVM中的QJVM要周期性的执行GC(垃圾攉?来清除不再被引用的Java对象。在GCq行时Tomcat会ȝQ如果在讄q接池中的连接的最大等待时?MaxWait)于GC的运行时间的话那么你很可能在使用数据库连接时p|。推荐将q接的超时时间设|成10?5U?br />注意q接的超时时间与被遗弃的q接的超时时间的区别?br /> 重复关闭连接引发的异常
q种情况发生在当响应一个客Lh时从数据库连接池里取得了q接但是关闭了两ơ。用连接池中的q接与用直接与数据库徏立的q接是不一LQ连接池中的q接在释放时只是连接返回到q接池而不是释放连接的资源。Tomcat使用多线E来处理q发的请求,以下实例演示了一个在Tomcat中可以导致出错的q程Q?br />hA在线EA中运行ƈ从连接池中得C个连?br />hA关闭了这个连?br />JVM转到U程B
hB在线EB中运行ƈ取得一个连?q个q接是请求A刚刚q回的那?
JVM转到U程A
hA在finally块中又一ơ关闭连?因ؓW一ơ没有设|连接引用ؓnull)
JVM转到U程B
hB试图使用得到的连接但q接已经被请求Aq回Cq接池中所以请求B的操作失?br />以下是一D公认的恰当的代码可以避免以上的问题
- Connection conn = null;
- Statement stmt = null; // Or PreparedStatement if needed
- ResultSet rs = null;
- try {
- conn = ... get connection from connection pool ...
- stmt = conn.createStatement("select ...");
- rs = stmt.executeQuery();
- ... iterate through the result set ...
- rs.close();
- rs = null;
- stmt.close();
- stmt = null;
- conn.close(); // Return to connection pool
- conn = null; // Make sure we don't close it twice
- } catch (SQLException e) {
- ... deal with errors ...
- } finally {
- // Always make sure result sets and statements are closed,
- // and the connection is returned to the pool
- if (rs != null) {
- try { rs.close(); } catch (SQLException e) { ; }
- rs = null;
- }
- if (stmt != null) {
- try { stmt.close(); } catch (SQLException e) { ; }
- stmt = null;
- }
- if (conn != null) {
- try { conn.close(); } catch (SQLException e) { ; }
- conn = null;
- }
- }

]]>