使用连接池

连接池是一种创建和管理多个(a pool of )连接的技术,这些连接是为任何需要它们的线程准备的。连接池不会马上关闭连接,而是将连接保存在一个pool中,这样可以很高效地服务下一个连接。除此之外,连接池还有很多好处,例如,控制资源的使用。

当开发基于Web的应用程序时,没有理由不使用连接池,包括ZK应用程序。

连接池的概念很简单:配置,连接及关闭。打开和关闭一个连接与点对点(ad-hoc )方法很相似,而配置依赖于使用的Web服务器和数据库。

打开及关闭一个连接

配置好连接池(将会在下面的章节讨论)之后,你可以使用JNDI 获取一个连接,如下。

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.zkoss.zul.Window;

public class MyWindows extends Window {
   private Textbox name, email;
   public void onCreate() {
      //initial name and email
      name = getFellow("name");
      email = getFellow("email");
   }
   public void onOK() throws Exception {
      DataSource ds = (DataSource)new InitialContext()
            .lookup("java:comp/env/jdbc/MyDB");
         //Assumes your database is configured and
         //named as "java:comp/env/jdbc/MyDB"

      Connection conn = null;
      Statement stmt = null;
      try {
         conn = ds.getConnection();
         stmt = conn.prepareStatement("INSERT INTO user values(?, ?)");

         //insert what end user entered into database table
         stmt.set(1, name.value);
         stmt.set(2, email.value);

         //execute the statement
         stmt.executeUpdate();
         stmt.close(); stmt = null;
            //optional because the finally clause will close it
            //However, it is a good habit to close it as soon as done, especially 
            //you might have to create a lot of statement to complete a job
      } finally { //cleanup
         if (stmt != null) {
            try {
               stmt.close();
            } catch (SQLException ex) {
               //(optional log and) ignore
            }
         }
         if (conn != null) {
            try {
               conn.close();
            } catch (SQLException ex) {
               //(optional log and) ignore
            }
         }
      }
   }
}

[注]:

  1. 使用之后关闭语句和连接是很重要的。

  2. 使用多个连接,你可以同时访问多个数据库。依赖于配置和J2EE/Web服务器,这些连接甚至可以形成一个分布式事务处理(distributed transaction)。

配置连接池

连接池的配置随J2EE/Web/数据库服务器的不同而不同。这里我们说明其中一些的配置。你需要参考(consult)你使用的服务器的文档。

Tomcat 5.5 + MySQL

为配置Tomcat 5.5配置连接池,你必须编辑$TOMCAT_DIR/conf/context.xml [66],,在<Context>元素的下添加下面的内容。标记为蓝色的的信息依赖于你的安装,且通常需要修改。

<!-- The name you used above, must match _exactly_ here!
   The connection pool will be bound into JNDI with the name
   "java:/comp/env/jdbc/MyDB"
-->
<Resource name="jdbc/MyDB" username="someuser" password="somepass" 
   url="jdbc:mysql://localhost:3306/test" 
   auth="Container" defaultAutoCommit="false" 
   driverClassName="com.mysql.jdbc.Driver" maxActive="20" 
   timeBetweenEvictionRunsMillis="60000" 
   type="javax.sql.DataSource" />
</ResourceParams>

然后在web.xml内,你需要在<web-app>元素下添加下面的内容。

<resource-ref>
  <res-ref-name>jdbc/MyDB</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

JBoss + MySQL

下列的指令基于MySQL 5.0 参考手册的23.3.4.3 章节(section 23.3.4.3 of the reference manual of MySQL 5.0)。

为JBoss配置连接池,你必须在deploy ($JBOSS_DIR/server/default/deploy)目录下添加一个新文件。文件名要以"-ds.xml"结尾,即告诉JBoss将此文件部署为JDBC数据源。文件必须包含下列内容。标记为蓝色的的信息依赖于你的安装,且通常需要修改。

<datasources>
    <local-tx-datasource>
        <!-- This connection pool will be bound into JNDI with the name
             "java:/MyDB" -->
        <jndi-name>MyDB</jndi-name>
        <connection-url>jdbc:mysql://localhost:3306/test</connection-url>
        <driver-class>com.mysql.jdbc.Driver</driver-class>
        <user-name>someser</user-name>
        <password>somepass</password>

        <min-pool-size>5</min-pool-size>

        <!-- Don't set this any higher than max_connections on your
         MySQL server, usually this should be a 10 or a few 10's
         of connections, not hundreds or thousands -->

        <max-pool-size>20</max-pool-size>

        <!-- Don't allow connections to hang out idle too long,
         never longer than what wait_timeout is set to on the
         server...A few minutes is usually okay here,
         it depends on your application
         and how much spikey load it will see -->

        <idle-timeout-minutes>5</idle-timeout-minutes>

        <!-- If you're using Connector/J 3.1.8 or newer, you can use
             our implementation of these to increase the robustness
             of the connection pool. -->

        <exception-sorter-class-name>com.mysql.jdbc.integration.jboss.ExtendedMysqlExceptionSorter</exception-sorter-class-name>
        <valid-connection-checker-class-name>com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker</valid-connection-checker-class-name>

    </local-tx-datasource>
</datasources>

JBoss + PostgreSQL

<datasources>
   <local-tx-datasource>
   <!-- This connection pool will be bound into JNDI with the name
        "java:/MyDB" -->
   <jndi-name>MyDB</jndi-name>

   <!-- jdbc:postgresql://[servername]:[port]/[database name] -->
   <connection-url>jdbc:postgresql://localhost/test</connection-url>

   <driver-class>org.postgresql.Driver</driver-class>
   <user-name>someuser</user-name>
   <password>somepass</password>
   <min-pool-size>5</min-pool-size>
   <max-pool-size>20</max-pool-size>
   <track-statements>false</track-statements>
   </local-tx-datasource>
</datasources>