跳转至

连接池和数据源

连接池和数据源

JDBC 2在附加的可选包(也称为JDBC 2.0 标准扩展)中引入了标准连接池功能。此后,核心JDBC 3 API中包含了该特性。

总览

JDBC API提供了用于连接池的客户端和服务器接口。客户端接口是javax.sql.DataSource,这是通常是应用程序获取池化数据库连接的接口。服务器接口是javax.sql.ConnectionPoolDataSource,这是大多数应用程序服务与SeaboxSQL™JDBC驱动程序连接的接口。

在应用程序服务中,通常将引用SeaboxSQL™ConnectionPoolDataSource实现。而应用程序组件通常会请求应用服务(而非SeaboxSQL™)实现的DataSource。

对于没有应用服务的环境,SeaboxSQL™提供了两种DataSource的实现,应用程序可以直接使用它们。一种实现执行连接池,而另一种实现仅通过DataSource接口提供对数据库连接的访问,而无需任何池。同样,除非应用程序服务不支持ConnectionPoolDataSource接口,否则不应使用这些实现。

应用程序服务ConnectionPoolDataSource

SeaboxSQL™包含一个名为com.seaboxsql.ds.SDConnectionPoolDataSourceConnectionPoolDataSource实现。

JDBC要求通过JavaBean属性配置ConnectionPoolDataSource,如表 ConnectionPoolDataSource配置属性所示,因此每个属性都有get和set方法。

表 ConnectionPoolDataSource配置属性

属性 类型 描述
serverName STRING SeaboxSQL™ 数据服务主机名
databaseName STRING SeaboxSQL™ 数据库名
portNumber INT SeaboxSQL™ 数据库侦听的TCP端口(使用0表示采用默认端口)
user STRING 建立连接使用的用户名
password STRING 建立连接使用的密码
ssl BOOLEAN 使用ssl加密连接时设为'true'(默认false)
sslfactory STRING 自定义javax.net.ssl.SSLSocketFactory 类名(参考“Custom SSLSocketFactory”)
defaultAutoCommit BOOLEAN 连接返回给调用者是,是否启动自动提交。默认为false,禁用自动提交。

许多应用程序服务器使用属性-值的语法来配置这些属性,因此将属性作为文本块输入并不罕见。 如果应用程序服务器提供了一个用于输入所有属性的区域,则可能会这样列出它们:

serverName=localhost
databaseName=test
user=testuser
password=testpassword

或者,如果将分号用作分隔符而不是换行符,则它可能看起来像这样:

serverName=localhost;databaseName=test;user=testuser;password=testpassword

应用程序数据源

SeaboxSQL™包括DataSource的两种实现,如表11.2“ DataSource实现”所示。一个做池,另一个不做池。当客户端调用close方法时,池实现实际上并没有关闭连接,而是将连接返回到可用连接池中,供其他客户端使用。这避免了重复打开和关闭连接的任何开销,并允许大量客户端共享少量数据库连接。

这里提供的池化数据源实现并没有提供最丰富的功能属性。在池本身关闭之前,连接永远不会关闭,也没有办法缩小池。同样,不对为默认配置用户以外的其他用户请求连接进行池化。其错误处理有时无法从池中删除断开的连接。通常,不建议使用SeaboxSQL™提供的连接池。检查您的应用程序服务或查看更优秀的jakarta commons DBCP项目。

表 DataSource实现

池化 实现的类
No `org.seaboxsql.ds.SDSimpleDataSource
Yes `org.seaboxsql.ds.SDPoolingDataSource

两种实现都使用相同的配置方案。 JDBC要求通过JavaBean属性配置数据源,如表 数据源配置属性所示,因此每个属性都有get和set方法。

表 数据源配置属性

属性 类型 描述
serverName STRING SeaboxSQL™ 数据库服务主机名
databaseName STRING SeaboxSQL™ 数据库名
portNumber INT SeaboxSQL™ 数据库侦听的TCP端口(使用0表示采用默认端口)
user STRING 建立连接使用的用户名
password STRING 建立连接使用的密码
ssl BOOLEAN 使用ssl加密连接时设为'true'(默认false)
sslfactory STRING 自定义javax.net.ssl.SSLSocketFactory 类名(参考[“Custom SSLSocketFactory”]

例 数据源代码示例展示了一个典型的使用池化DataSource的应用代码

例 数据源代码示例

在代码中初始化一个池化的DataSource的方式如下:

SDPoolingDataSource source = new SDPoolingDataSource();
source.setDataSourceName("A Data Source");
source.setServerName("localhost");
source.setDatabaseName("test");
source.setUser("testuser");
source.setPassword("testpassword");
source.setMaxConnections(10);

接下来,使用来自池的连接代码如下所示。 请注意,最终关闭连接至关重要。 否则,该池将“泄漏”连接,并最终将所有客户端锁定。

Connection conn = null;try{
    conn = source.getConnection();
    // use connection}catch (SQLException e){
    // log error}finally{
    if (con != null)
    {
        try { conn.close(); } catch (SQLException e) {}
    }
}

Tomcat设置

注意

必须将SeaboxSQL 4和5中的seaboxsql.jar文件都放在$CATALINA_HOME/common/lib中。

在这两个tomcat实例中进行设置最简单方法是使用Tomcat附带的管理Web应用程序,只需将数据源添加到要在其中使用它的上下文中即可。

Tomcat 4的安装程序将以下内容放在conf/server.xml中的标记内

<Resource name="jdbc/seabox" scope="Shareable" type="javax.sql.DataSource"/><ResourceParams name="jdbc/seabox">
    <parameter>
        <name>validationQuery</name>
        <value>select version();</value>
    </parameter>
    <parameter>
        <name>url</name>
        <value>jdbc:seaboxsql://localhost/davec</value>
    </parameter>
    <parameter>
        <name>password</name>
        <value>davec</value>
    </parameter>
    <parameter>
        <name>maxActive</name>
        <value>4</value>
    </parameter>
    <parameter>
        <name>maxWait</name>
        <value>5000</value>
    </parameter>
    <parameter>
        <name>driverClassName</name>
        <value>com.seaboxsql.Driver</value>
    </parameter>
    <parameter>
        <name>username</name>
        <value>davec</value>
    </parameter>
    <parameter>
        <name>maxIdle</name>
        <value>2</value>
    </parameter></ResourceParams>

为Tomcat 5设置时,可以使用上述方法,除了它位于标记内的标记。 例如。 <Host> ... <DefaultContext> ...

另外,还有一个conf/Catalina/hostname/context.xml文件。 例如,http//localhost:8080/servlet-example的目录为$CATALINA_HOME/conf/Catalina/localhost/servlet-example.xml文件。 在此文件内,将上述xml放在标记内

然后,使用以下代码访问连接。

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");

            // /jdbc/seabox is the name of the resource above
            DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/seabox");

            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;}
}

数据源和JNDI

所有ConnectionPoolDataSource和DataSource实现都可以存储在JNDI中。对于非池实现,每次从JNDI检索对象时都会创建一个新实例,其设置与存储的实例相同。对于池实现,只要有可用的实例就会被取回(例如,从JNDI检索池的不同JVM),否则将创建具有相同设置的新实例。

在应用程序服务环境中,通常,应用程序服务器的DataSource实例将存储在JNDI中,而不是在SeaboxSQL™ ConnectionPoolDataSource实现中。

在应用程序环境中,应用程序可以将数据源存储在JNDI中,这样就不必对所有应用组件可能用到的数据源创建应用。例 DataSource JNDI代码示例中给出了一个例子。

例 DataSource JNDI代码示例

初始化池数据源并将其添加到JNDI的应用程序代码如下所示:

SDPoolingDataSource source = new SDPoolingDataSource();
source.setDataSourceName("A Data Source");
source.setServerName("localhost");
source.setDatabaseName("test");
source.setUser("testuser");
source.setPassword("testpassword");
source.setMaxConnections(10);
new InitialContext().rebind("DataSource", source);

从池中使用连接的代码如下:

Connection conn = null;try{
    DataSource source = (DataSource)new InitialContext().lookup("DataSource");
    conn = source.getConnection();
    // use connection}catch (SQLException e){
    // log error}catch (NamingException e){
    // DataSource wasn't found in JNDI}finally{
    if (con != null)
    {
        try { conn.close(); } catch (SQLException e) {}
    }
}