47.1. 数据库连接池开发

47.1.1. 概述

JDBC 是执行SQL 语句的JAVA API,由一系列使用Java 编写的类和接口组成。JDBC为工具和数据库开发人员提供标准API并使使用纯JAVA API 编写数据库应用成为可能。JDBC 是个低级的接口,意味着它只是用来直接调用SQL 命令。另外,JDBC 也作为诸如JMS和EJB等高级界面和接口的基础。

金蝶Apusic应用服务器支持JDBC4.0版本,JDBC4.0是本文档书写时JDBC API最新发布版。 有关JDBC3.0的特性,参见JDBC4.0特性

JAVA 数据库连接(JDBC)提供对后台数据库的访问,JAVA 应用通过使用JDBC驱动程序(数据库供应商指定的数据库接口)取得对JDBC 的使用。尽管任何JAVA 应用都可以装载JDBC 驱动程序、连接数据库、执行数据库操作,Apusic应用服务器还提供一个高效的JDBC 数据库连接池。JDBC 数据库连接池是一个通过金蝶Apusic应用服务器管理的JDBC连接的命名组。金蝶Apusic应用服务器启动时打开JDBC 数据库连接并把他们加入到JDBC数据库连接池中。当应用请求一个连接时,应用从池中取得连接,使用后将连接返回到池中以备被其他应用使用。通常,建立数据库连接是个耗费时间和资源的操作。因此,通过限制连接操作次数的连接池,能提高服务器的效率。要在JNDI命名树中登记一个连接池,只需为它定义一个DataSource对象。Java 客户端应用通过对DataSource名字执行JNDI查找,即可从连接池中获取连接。服务器端Java类使用标准JDBC 接口,它是一个一般化的JDBC驱动程序接口。即使在数据层改变了数据库的类型,也不用更改应用的代码,使应用具有更强的可移植特性。

金蝶Apusic应用服务器提供已准备好的对DBMS 的连接池。连接池启动时连接即建立,消除了应用运行时建立连接的拥挤状态。可以从如HTTPServlet、EJB 等服务器端应用使用连接池和通过Apusic 的RMI 服务使用独立Java 客户端应用程序访问连接池。连接池需要一个两层的JDBC驱动程序生成Apusic 到DBMS 的连接。

47.1.2. 使用JDBC连接池

47.1.2.1. 服务器端JDBC应用

对于从服务器端应用如HTTP Servlet 等使用数据库连接池可使用JNDI 和DataSource对象,下例将在一个Servlet中使用数据源来演示从服务器端应用数据库连接池。

import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;
import java.sql.*;
import javax.naming.*;

public class ConnectionPoolServlet extends
javax.servlet.http.HttpServlet{
	public void service(HttpServletRequest req,
		HttpServletResponse res)throws IOException{
	try{
	//取得InitialContext 对象
	Context ctx=new InitialContext();
	//通过JNDI 取得数据源
	DataSource datasource=(DataSource)
	ctx.lookup("jdbc/oracle");
	//通过数据源取得数据库连接
	Connection conn=datasource.getConnection();
	...
	}
}
...

47.1.2.2. 客户端JDBC应用

金蝶Apusic应用服务器增加了JDBC 连接的远程访问接口,用户可以在Java客户端程序中通过RMI 调用JDBC连接池中的连接。

第一,如要实现在Java 客户端程序中通过RMI 调用JDBC连接池中的连接,必须在datasources.xml中,为相应的数据库连接设定其通过远程连接需要的户认证标记。方法如下,首先设定将使用此连接的Apusic组或用户,如:your_group<组名>或your_user<用户名>;然后在datasources.xml中添加<remote-acl>标记及其元素。范例如下:

<remote-acl>
    <user>username</user>
</remote-acl>
或
<remote-acl>
    <group>groupname</group>
</remote-acl>

第二,在客户端Java 程序中,将相关的验证信息加入到环境参数中,即Apusic用户名及密码。范例如下:

import javax.sql.*;
import java.sql.*;
import javax.naming.*;
import javax.rmi.*;

public class RMIJdbc
public static void main(String[] args){
	Hashtable env=new Hashtable();
	Context initCtx=null;
	DataSource datasource=null;
	try{
		env.put(Context.INITIAL_CONTEXT_FACTORY,"com.apusic.naming.jndi.CNContextFactory");
		env.put(Context.PROVIDER_URL,"iiop://APUSIC_ADDRESS:6888");
		//插入相关验证信息
		env.put(Context.SECURITY_CREDENTIALS,"your_username" ) ;
		env.put(Context.SECURITY_PRINCIPAL,"your_password");
		initCtx=new InitialContext(env);
		//通过RMI 取得数据库连接
		datasource=(DataSource)initCtx.lookup("jdbc/sample")
		Connection conn=datasource.getConnection();
	}catch(Exception e){
		e.printStackTrace();
	}
	...
}

最后,编译客户端代码并执行。如不能连接,请检查是否可以通过servlet 或EJB 进行连接, 可参考上节"2.1服务器端应用"中相关内容。

47.1.3. 范例

下面的例子是JAVA应用程序直接访问数据源的例子。数据库是Oracle,表是scott下的customer。

第一步:建立数据源。

在Apusic管理工具中,打开“驾驶舱”-->“数据源”-->“新增数据源”,在“添加数据源”界面下连接池中填写如下信息:

如果需要提供可供远程访问的数据源,请参考第 33.2.1 节 “编辑datasources.xml文件”配置

第二步:JAVA应用程序代码:

/**
 * Title:        JDBCTest
 * Description:  JDBC Test
 * Copyright:    Copyright (c) 2003
 * Company:      Apusic
 * @author Michael
 * @version 1.0
 */
import java.util.*;
import javax.ejb.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;

public class JDBClient {
    private Connection con = null;
    private PreparedStatement prepStmt = null;

    /**
     * dbName 对应第一步在创建数据源时的“基本”表格中“连接池JNDI名”
     */
    private String dbName = "jdbc/sample";

    public JDBClient() {
    }

    public void run(){
    	try{
            Hashtable env = new Hashtable();

	 // url 中的localhost可以替换为任意可连通的已安装Apusic应用服务器的主机名或地址
            String url = "iiop://localhost:6888";
            env.put(Context.INITIAL_CONTEXT_FACTORY,"com.apusic.naming.jndi.CNContextFactory");
            env.put(Context.PROVIDER_URL, url);

	 // 下面的用户必须是在Apusic中存在的,并且是在“远程访问控制用户列表”中定义的用户
            env.put(Context.SECURITY_PRINCIPAL ,"scott");
            env.put(Context.SECURITY_CREDENTIALS ,"tiger");
            InitialContext ic = new InitialContext(env);
            DataSource ds = (DataSource) ic.lookup(dbName);
            con =  ds.getConnection();

           // customer 是Oracle自带的scott下的表
	   String selectStatement = "select * from customer" ;
            prepStmt = con.prepareStatement(selectStatement);

            ResultSet rs = prepStmt.executeQuery();
	 		System.out.println("FIRSTNAME   " + "LASTNAME" );
            while (rs.next()) {
                 System.out.println(rs.getString("FIRSTNAME") +"   "+ rs.getString("LASTNAME"));
            }
        }catch(Exception e){
            e.printStackTrace() ;
        } finally {
  	   cleanup(con,prepStmt);
        }
    }

    private void cleanup(Connection con, PreparedStatement ps) {
        try {
	  if (ps != null) ps.close();
        } catch (SQLException e) {
	  e.printStackTrace() ;
        }

        try {
	  if (con != null) con.close();
        } catch (SQLException e) {
	  e.printStackTrace() ;
        }
    }

    public static void main(String[] args) {
        JDBClient _jdbctest = new JDBClient();
        _jdbctest.run();
    }
}

正确的执行结果为:

FIRSTNAME LASTNAME

sunny sunny Yuan

Judy Judy Li

John John Wan

Peter Peter Miao