引用 http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0512zhanghzh/
2005 年 1 月 04 日
IBM DB2 数据库在 J2EE Web Application 中应用日趋广泛,如何快速高效地访问 IBM DB2 数据库成为开发人员关心的话题。本文首先介绍如何快速的利用 IBM DB2 提供的 JDBC 驱动程序通过 Java API 进行数据库接口开发,然后进一步介绍如何在 WebSphere Application Server 6.0 中配置数据库连接池 (Connection Pool),更加高效地访问 IBM DB2 数据库,最后通过一致的代码接口,使得 Web 开发人员更加透明的访问 IBM DB2 数据库。
IBM DB2 数据库在 J2EE Web Application 中应用日趋广泛,如何快速高效地访问 IBM DB2 数据库成为开发人员关心的话题。本文首先介绍如何快速的利用 IBM DB2 提供的 JDBC 驱动程序通过 Java API 进行数据库接口开发,然后进一步介绍如何在 WebSphere Application Server 6.0 中配置数据库连接池 (Connection Pool),更加高效地访问 IBM DB2 数据库,最后通过一致的代码接口,使得 Web 开发人员更加透明的访问 IBM DB2 数据库。
本文的示例环境:
WebSphere Application Server 6.0 on RedHat AS3.0
IBM DB2 Universal Database v8.2
Rational Software Architect v6.0
![]() ![]() |
![]()
|
对任何一个典型的数据库,通过 JDBC 驱动程序访问必须经过如下步骤:
1) 导入 JDBC 驱动程序;
2) 建立数据库连接;
3) 执行 SQL 语句;
4) 获取执行结果;
5) 关闭数据库连接。
下面详细描述各个步骤。
打开 Rational Software Architect, 单击 "File",然后选择 "Project",再选择 "Java Project",单击 "Next",然后输入项目名字,比如 "DB2Access",然后单击 "Finish"。
单击 "DB2Access" 项目,单击右键,然后单击 "Properties",然后选择 "Java Build Path",选中 "Libraries" 标签;
单击 "Add External Jars",选择目录到 DB2 安装目录下的 lib 库,通常为 C:/Program Files/IBM/SQLLIB/java,选择 "db2jcc.jar","db2jcc_license_cisuz.jar","db2jcc_license_cu.jar",然后单击"OK"。
至此,已经成功引入 IBM DB2 JDBC 驱动程序。
右键单击 DB2Access 项目,然后单击 "New",选择 "Class",在 package 中输入 com.test,在 Name 中输入 ConnectionProvider,然后单击 "OK"。己建好数据库名字 DBTest,建有表 IDTable,表中有一字段为 ID。为 ConnectionProvider 类新加方法 getConnectionProvider(),具体代码如下:
public static final String DB2DRIVER="com.ibm.db2.jcc.DB2Driver"; public static final String DB2URL="jdbc:db2://10.1.1.54:50000/GBPMDB"; public static final String DB2USER="db2inst1"; public static final String DB2PASSWORD="passw0rd"; public static Connection getConnectionByJDBC() throws SQLException{ Connection conn = null; try { Class.forName(DB2DRIVER).newInstance(); conn= DriverManager.getConnection(DB2URL, DB2USER, DB2PASSWORD); System.out.println("Andrew: getConnection ok");//$NON-NLS-1$ } catch (InstantiationException e) { System.out.println("Andrew: InstantiationException!");//$NON-NLS-1$ } catch (IllegalAccessException e) { System.out.println("Andrew: IllegalAccessException!");//$NON-NLS-1$ } catch (ClassNotFoundException e) { System.out.println("Andrew: ClassNotFoundException!");//$NON-NLS-1$ } return conn; } |
右键单击 DB2Access 项目,然后单击 "New",选择 "Class",在 package 中输入com.test,在Name中输入 RequestIDManager,然后单击 "OK"。
假定数据库里有一张表为 Request 表,该表有一个字段为 RequestID,类型为 Integer。 添加 getRequestID() 函数,取得该域的值,具体代码如下:
private static final String getRequestIDSqlString = "SELECT REQUESTID FROM REQUEST"; public static String getRequestID(){ String id = null; Connection conn = null; Statement sm = null; ResultSet rs = null; try{ conn = ConnectionProvider.getConnection(); sm = conn.createStatement(); rs = sm.executeQuery(getRequestIDSqlString); if(rs.next()){ id = rs.getString(1); System.out.println("Andrew: RequestID = "+id);//$NON-NLS-1$ }else{ System.out.println("Andrew: No record ID exists!");//$NON-NLS-1$ } }catch(SQLException e){ System.out.println("Andrew: SQL exception "+e.toString());//$NON-NLS-1$ }finally{ try { if(null != rs){ rs.close(); } if(null != sm){ sm.close(); } if(null != conn){ conn.close(); } } catch (SQLException e) { } } return id; } |
添加新方法 updateRequestID() 函数,该函数将 RequestID 字段的值自增 1,具体代码如下:
private static final String updateRequestIDSqlString = "update request set requestid=requestid+1"; public static boolean updateRequestID(){ String id = null; Connection conn = null; Statement sm = null; ResultSet rs = null; boolean ret = false; try{ conn = ConnectionProvider.getConnection(); sm = conn.createStatement(); int affectedCount = sm.executeUpdate(updateRequestIDSqlString); if(affectedCount > 0) ret = true; System.out.println("Andrew: update requestID ok, affectedCount = "+affectedCount);//$NON-NLS-1$ }catch(SQLException e){ System.out.println("Andrew: SQL exception "+e.toString());//$NON-NLS-1$ }finally{ try { if(null != rs){ rs.close(); } if(null != sm){ sm.close(); } if(null != conn){ conn.close(); } } catch (SQLException e) { } } return ret; } |
上面的两个示例代码中的 Finally 块里代码即为关闭数据库连接操作。
finally{ try { if(null != rs){ rs.close(); } if(null != sm){ sm.close(); } if(null != conn){ conn.close(); } } catch (SQLException e) { } } |
可以在 ReportIDManager 中写 Main 函数,测试 getRequestID 和 updateRequestID方法,具体代码如下:
public static void main(String[] args) { getRequestID(); updateRequestID(); } |
以 Java application 的方式运行该程序,得到输出类似如下:
Andrew: getConnection ok Andrew: RequestID = 15912 Andrew: getConnection ok Andrew: update requestID ok, affectedCount = 1 |
至此,我们已经用 JavaAPI 完成读写 IBM DB2 数据库的基本操作,可以将 com.test 导出为 jar 包,供 Web Application 以及其他 J2EE 程序使用。
![]() ![]() |
![]()
|
Web Application 往往用数据库存储的信息生成 Web 页面,每一个页面请求导致一次数据库访问。连接数据库需要开销一定的通讯和内存资源,还必须完成用户验证这类任务,因而往往成为非常耗时的操作,而关闭网页时又需要关闭与数据库建立的连接。
数据库连接池模式正是为了解决资源的频繁分配﹑释放所造成的问题。数据库连接池的基本思想就是为数据库连接建立一个"缓冲池"。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从"缓冲池"中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,并有效的提高系统测试性能。
一个典型的连接池中的连接过程如图所示:
首先由用户发出请求,比如 HTTP 请求 JSP 页面,对应的 JSP 页面需要进行数据库操作,向连接池管理器发出请求数据库连接,连接池数据库从数据库连接池中获取一条数据库连接,返回给JSP,当该数据库操作结束,JSP页面释放数据库连接,连接库管理器将该连接放回数据库连接池。建立释放数据库连接的过程中,连接池管理器没有直接访问数据库,而是访问数据库连接池,即从数据库连接池中获得连接,释放连接到数据库连接池。数据库连接池和数据库之间由 J2EE 容器来管理,下文中可以看到 WebSphere Application Server 中如何配置数据库连接池的参数属性。连接池管理器提供给 J2EE 应用程序获取连接和释放连接的编程接口和直接访问数据库的 Java 编程接口完全一致,因此,数据库连接池技术对 J2EE 应用程序来说几乎是透明的(除了初始化阶段有所不同),应用程序完全像直接访问数据库一样访问数据库连接池。
![]() ![]() |
![]()
|
在 WebSphere Application Server 6.0 中配置连接池
WebSphere Application Server 很好的支持连接池模式,由容器来管理与数据库之间的连接,并在性能上有明显的改善。下面介绍如何在 WebSphere Applicatin Server 6.0 中为 IBM DB2 配置连接池。
1) 通过 http://wasip:9060/admin 登陆控制台窗口,点击 "Resource",再点击 "JDBC Provider";
2) 单击 "new",在 "Step1 Select Database type" 中选择 "DB2",在 "Step2 Select the provider type" 中选择 "DB2 JDBC Universal JDBC Connection Provider",在 "Step 3 Select the implementation type" 中选择 "Connection Pool data source";
3) 单击 "next",在 "Name" 中输入该 JDBC Provider 在 WebSphere Application Server 中的名字如 "DB2ConnectionPool Test",其他为默认值;
4) 点击 "Apply";
5) 点击 "Data Source";
6) 单击 "New",在 "Name" 中输入 "DB2ConnectionPool Test",在 "JNDI Name" 中输入 "jdbc/DB2ConnectionPool";
7) 在 "Database Name" 中输入 "TestDB",在 "Server Name" 中填入 IBM DB2 所在的机器的地址,在 "Port" 中填入 IBM DB2 运行时监听的端口,一般为默认 50000;
8) 点击 "Apply";
9) 点击 "Related Items" 里的 "J2EE Conenctor Architecture(J2C) authentication data entries";
10) 点击 "New",在 "Alias" 中输入该认证的名字 "TestDB2ConnectionPoolAuth",在 user 和 password 中分别输入 IBM DB2 所需验证的用户名和密码;
11) 点击 "OK",在 "J2EE Connector Architecture (J2C) authentication data entries" 列表里可以看到新添加的认证数据项;
12) 点击导航栏的 "JDBC Provider",然后点击 "DB2ConnectionPool Test",然后点击 "Data Source",然后点击 "DB2ConnectionPoolTest",进入配置页面,在 "Component-managed authentication alias" 中选择 "localhostNode01/TestDB2ConnectionPoolAuth"。
13) 点击 "OK";
14) 点击 "Save" 保存所做配置;
15) 选中 DB2ConectionPoolTest 的复选框,然后单击 Test Connection,显示测试成功。
如果出现 ClassNotFoundException,快速解决方法是将 IBM DB2 JDBC 驱动文件db2jcc.jar","db2jcc_license_cisuz.jar","db2jcc_license_cu.jar")拷贝到 WebSphere Application Server 6.0 的库里,并重新启动 WebSphere Application Server;
16) 配置连接池具体属性。点击 "DB2ConnectionPool Test",然后在 "Additional Properties" 中点击 "Connection Pool Properties";
17) 可以设置最小连接数,最大连接数等属性,也可以使用默认配置。
至此,我们已经完成 WebSphere Application Server 中 Connection Pool 的配置。
![]() ![]() |
![]()
|
修改上文的 ConnectionProvider中的 getConnection 代码如下并新增初始化 JNDI lookup 代码如下:
public static final String CONNECTIONPOOL_JNDINAME = "java:comp/env/DB2ConnectionPool"; static{ initConnection(); } protected static void initConnection(){ try{ InitialContext ctx = new InitialContext(); connectionPoolDataSource=(DataSource) ctx.lookup(CONNECTIONPOOL_JNDINAME); System.out.println("Andrew: Init Connection Pool JNDI ok");//$NON-NLS-1$ }catch(NamingException ne){ System.out.println("Andrew: initConnectoin failed");//$NON-NLS-1 } } public static Connection getConnection() throws SQLException{ Connection conn = null; if(null != connectionPoolDataSource){ conn = connectionPoolDataSource.getConnection(); } if(conn == null){ throw new SQLException(); } return conn; } |
1) 单击 "File",然后单击 "Export…",选择 "Jar files",选择 DB2Access 的 com.test 包,填写 jar 包名字,如 DB2ConnectionPool.jar;
2) 单击 "Finish"。生成的 jar 包即可供 Web Application 调用。
1) 单击 "File",然后单击 "New",单击 "Project",选择 "Dynamic Web Project";
2) 单击 "Next",输入项目名字比如 "ConnectionPoolTestWeb";
3) 单击 "Finish";
4) 将 DB2ConnectionPool.jar 和IBM DB2 JDBC驱动文件 "db2jcc.jar","db2jcc_license_cisuz.jar","db2jcc_license_cu.jar")拷贝至 ConnectionPoolTestWeb 项目中的 WebContent/WEB-INF/lib 中;
5) 新建 "test.jsp",右键单击 "ConnectionPoolTestWeb",选择 "new",单击 "JSP File";
6) 输入 JSP 页面名称 test.jsp,单击 "Finish",JSP 上添加代码如下:
<%@ page import = "com.test.*" %> <BODY> before update: id = <%= RequestIDManager.getRequestID() %> <% RequestIDManager.updateRequestID(); %> <br> after update: id = <%= RequestIDManager.getRequestID() %> </BODY> |
7) 双击 WebContent/WEB-INF/Web.xml,选中 "Reference" 标签;
8) 单击 "Add",选择 "Resource environment Reference";
9) 单击 "Next",在 Name 中输入 " DB2ConnectionPool",在 Type 中选择 javax.sql.DataSource;
10) 点击 Finish;
11) 在 WebSphere Bindings 栏的 jndi name 中输入 jdbc/DB2ConnectionPool;
12) 保存 Web.xml 配置;
13) 将 ConnectionPoolTestWeb 项目导出为 Ear 包。单击 "File",选择 "Export…",单击 "Export…";
14) 选择 "EAR file",单击 "Next",选择 "ConnectionPoolTestWebEar" 项目,输入导出文件名字如 "ConnectionPoolTestWeb.ear";
15) 单击"Finish"。
4. 发布 ConnectionPoolTestWeb.ear
1) 登陆 http://wasip:9060/admin;
2) 单击 "Install new application";
3) 安装过程和发布普通 EAR 包一样。值得注意的是安装的第三步 "Map Resource env entry references to resource",勾中复选框即可;
4) 安装完毕后保存 WebSphere Application Server 配置;
5) 并启动 ConnectionPoolTestWeb 项目。
1) 在浏览器中输入 http://wasip:9080/ConnectionPoolTestWeb/test.jsp;
2) 运行结果如下:
![]() ![]() |
![]()
|
我们对 getRequestID 和 updateRequestID 进行的两个版本进行性能测试。测试前,务必去掉代码中的打印等调试语句。测试 getRequestID,updateRequestID 方法,每个方法迭代 100 次,共测试 5 次。
测试代码:
int times = 100; Date beginGetRequestID = new Date(); for(int i = 0; i < times; ++i){ getRequestID(); } Date endGetRequestID = new Date(); long elapsedGetRequestID = endGetRequestID.getTime()-beginGetRequestID.getTime(); System.out.println("Andrew: getRequestID consumed = "+ elapsedGetRequestID +"ms"); Date beginUpdateRequestID = new Date(); for(int i = 0; i < times; ++i){ updateRequestID(); } Date endUpdateRequestID = new Date(); long elapsedUpdateRequestID = endUpdateRequestID.getTime()-beginUpateRequestID.getTime(); System.out.println("Andrew: updateRequestID consumed = "+ elapsedUpdateRequestID +"ms"); |
测试结果(单位 ms):
图解:(NCP)为该方法不采用连接池实现版本,(CP)为该方法采用连接池实现版本。
测试分析:
从测试数据可以看出,在短查询操作 getRequestID 方法中,使用连接池技术性能提高了 25 倍,耗时仅为非连接池技术的 4%,updateRequestID 操作使用连接池技术后性能提高了 9 倍,耗时仅为非连接池技术的 11%!我们采用 T1 表示建立数据库连接所花费时间,T2 表示执行 SQL 语句操作数据库花费时间,T3 表示关闭数据库连接所花费时间,而 T 表示整个操作数据库方法所花费总时间。用 _CP 表示连接池版本实现,_NCP 表示非连接池实现版本,P=连接池技术耗时/非连接池技术耗时,则 P = (T1_CP+T2+T3_CP)]/T_NCP,从连接池中获取释放连接耗时 (T1+T3) 可以看成一个常数 C,那么 P=(T2+C)/T_NCP。由此可见,当执行数据库操作部分在整个操作中占的比例越小,性能提高的越明显。此类短操作包括一般数据查询操作,少量数据更新,而 Web Application 对数据库的操作有很大部分为此类操作,比如查询更新某用户信息等,示例程序的 getRequest,updateRequest 均为典型短操作方法。
![]() ![]() |
![]()
|
通过 Java API,以 JDBC 的方式访问数据库编程简单,而利用 WebSphere Application Server 6.0 容器管理数据库连接池,具有可重用性,高效性,特别适合复杂 J2EE 应用程序。
![]() | ||
| ![]() | 张黄瞩,熟悉 WebSphere Business Integration Server Foundation,WebSphere Process Server v6.0,对业务整合有较大兴趣。爱好篮球。您可以通过 zhanghuangzhu@gmail.com 与他联系。 |