以文本方式查看主题
- 太广软件技术论坛 (http://www.521tg.com/bbs/index.asp)
-- JAVA语言 (http://www.521tg.com/bbs/list.asp?boardid=7)
---- 基于Java的数据库连接池组件 (http://www.521tg.com/bbs/dispbbs.asp?boardid=7&id=105)
--------------------------------------------------------------------------------
-- 作者:冯太广
-- 发布时间:2005-3-14 14:28:38
-- 基于Java的数据库连接池组件
摘要:首先讲述了数据库连接池的工作原理及程序流程,然后用Java实现了数据库连接池组件,最后说明了该组件的使用方法。
关键词:数据库;连接池;Java;组件
Java语言以其面向对象、安全性、平台无关性以及多线程和分布式等特性使其成为开发数据库应用的一种优秀开发语言,而JDBC(Java Database Connectivity)是Java应用程序与数据库的沟通桥梁。本文将讨论如何利用Java及数据库连接池技术使数据库应用系统具有较高的执行效率,并开发成Java组件方便用户使用。
1问题的提出
随着网络技术的深入发展以及B/S模式的成熟,现在绝大部分应用系统都涉及到数据库的相关操作,而使用JDBC API访问数据库的方法:首先,建立数据库连接;然后,利用SQL语句对数据库进行操作;最后,断开数据库连接。其中建立数据库的连接会执行协议握手、验证用户、打开磁盘文件、创建高速缓存等工作,是整个应用系统中代价最大的操住之一。
在一个简单的数据库应用中由于数据库的访问不是很频繁,因此可以在需要的时候直接创建一个新的连接,使用完毕后关闭这个连接。这种访问方式不会带来显著的系统开销,而且具有简单可靠的特点;但是在一个有大量联机并发访问的应用系统中,对数据库的访问请求具有非常频繁而短暂的特点。在这种倩况下如果还是简单地为每个请求单独创建新连接,在使用完后关闭连接,由此带来系统开销将会导致系统性能的显著下降,严重时还可能导致系统瘫痪。问题的根源在于对连接资源的低效管理,为了有效地解决这个问题,我们提出了数据库连接池技术,通过建立一个数据库连接池以及一套高效的连接使用管理策略使得一个数据库连接可以得到高效安全的复用,可以大大地提高系统效率。
2连接池原理
连接池实际上是在一个容器对象中建立一定数目的数据库连接对象。当需要使用数据库连接的时候,直接从连接池中取出空闲的连接对象供用户使用。当用户使用完毕后再把连接放回连接池中,节省了重新建立连接对象所花费的时间。连接池工作原理如图1所示。
首先应当初始化内含一定连接数量的连接池;在使用过程中如果池中的连接数量不够,再逐渐加入新的连接。由于池中的连接数量不能是无限的,当达到最大数量时,池中就不再增加新的连接。此时如果连接数量仍然不够,就只能等待别的连接被释放后再使用,即定义连接池中连接数量的上下界和连接超时时间。定义上下界可根据客户端的情况动态地使用资源,提高系统的效率。另外,同一个连接如果被使用的次数太多,可能会导致该连接的不稳定。所以需要设定一个连接可使用的最大次数。当使用次数达到最大次数后就将该连接关闭并从池中删除。
3连接池组件的实现
根据上述原理便可编写一个通用的连接池组件。本文采用了二个Java类和一个数据库配置文件(dbconfig.txt)实现数据库连接池组件。一个是ConnectionObject类,用来管理一个连接的状态:另外一个为ConnectionPool类,用来实现对连接池的管理。
图1 连接池工作原理图
ConnectionObject类的代码如下:
package com.db;
import java.sql.*;
import java.io.*;
public class ConnectionObject {
//数据库的连接
private Connection connection;
//连接状态:此连接当前是否被使用
private boolean isUse;
//此连接被使用的次数
private int useCount;
// 构造方法
public ConnectionObject(String url, String username, String password) {
try{
if(username.equals("")){
connection = DriverManager.getConnection(url);
}
else{
connection = DriverManager.getConnection(url,username,password);
}
}
catch(SQLException e){
System.err.print(e.getMessage());
}
//初始化连接状态为空闭
isUse = false;
//初始化使用次数为0
useCount = 0;
}
// getter和setter方法
public Connection getConnection(){
return connection;
}
public void setConnection(Connection connection){
this.connection = connection;
}
public boolean isIsUse() {
return isUse;
}
public void setIsUse(boolean isUse) {
this.isUse = isUse;
}
public void setUseCount(int useCount) {
this.useCount = useCount;
}
public int getUseCount() {
return useCount;
}
// 连接使用次数加1方法
public void addUseCount(){
useCount++;
}
}
数据库连接池ConnectionPool类实现如下:
package com.db;
import java.sql.*;
import java.io.*;
import java.util.*;
public class ConnectionPool {
//数据库驱动程序
private String driver = "";
//数据库url
private String url = "";
//数据库用户名
private String username = "";
//数据库密码
private String password = "";
//使用Vector对象作为连接池
private Vector pool = new Vector();
//初始化时,在连接池中建立的连接对象数目
private int connectionPoolSize;
//连接池中至多能建立的连接对象数目,即连接池的上限
private int connectionPoolMaxSize;
//数据连接至多能被使用的次数
private int connectionMaxUseCount;
//设置连接超时时间
private int timeout;
// 读取数据库配置信息
private void loadProp(){
//dbconfig.txt为数据库配置文件
InputStream is = getClass().getResourceAsStream("dbconfig.txt");
Properties props = new Properties();
try{
props.load(is);
}catch(Exception e){
System.err.println("不能读取数据库配置文件. 请确保dbconfig.txt存在!");
}
Enumeration propNames = props.propertyNames();
while (propNames.hasMoreElements()) {
String name = (String) propNames.nextElement();
if (name.enth(".driver")) {
String poolName = name.substring(0, name.lastIndexOf("."));
driver = props.getProperty(poolName + ".driver");
url = props.getProperty(poolName + ".url");
username = props.getProperty(poolName + ".user");
password = props.getProperty(poolName + ".password");
connectionPoolMaxSize = Integer.parseInt(props.getProperty(poolName + ".maxconnection"));
connectionPoolSize = Integer.parseInt(props.getProperty(poolName + ".minconnection"));
connectionMaxUseCount = Integer.parseInt(props.getProperty(poolName + ".connectionmaxusecount"));
timeout = Integer.parseInt(props.getProperty(poolName + ".timeout"));
}
}
}
// 创建连接对象,并初始化连接池
private void initPool(){
loadProp();
try{
Class.forName(driver);
}
catch(ClassNotFoundException e){
System.err.print(e.getMessage());
}
//创建connectionPoolSize个空闭的连接对象,并把它们加入连接池中
while(pool.size() < connectionPoolSize){
ConnectionObject newConn = new ConnectionObject(url, username, password);
pool.add(newConn);
}
}
// 构造方法
public ConnectionPool() {
initPool();
}
// 析构方法,释放所有的连接,清空连接池
public void finalize(){
for(int i = 0; i < pool.size(); i++){
ConnectionObject co = (ConnectionObject)pool.elementAt(i);
try{
co.getConnection().close();
}
catch(SQLException e){
System.err.print(e.getMessage());
}
co = null;
}
pool = null;
}
// 杳找连接对象在连接池中的序号
private int findConnectionID(Connection conn){
ConnectionObject co;
for(int i = 0; i < pool.size(); i++){
co = (ConnectionObject)pool.elementAt(i);
if(co.getConnection() == conn){
return i;
}
}
return -1;
}
// 用户释放连接的接口
public void realse(Connection conn){
int index = findConnectionID(conn);
if(index == -1){
return ;
}
ConnectionObject co = (ConnectionObject)pool.elementAt(index);
//若连接使用次数超过connectionMaxUseCount,将此连接从连接池中删除
if(co.getUseCount() >= connectionMaxUseCount){
pool.remove(index);
}
else{
//置该连接状态为空闭
co.setIsUse(false);
}
}
// 查找连接池,返回第一个空闭的连接,没有则返回null
private ConnectionObject getFreeConnection(){
for(int i = 0;i < pool.size(); i++){
ConnectionObject co = (ConnectionObject)pool.elementAt(i);
if(co.isIsUse() == false)
return co;
}
return null;
}
// 用户获取物理连接的接口
public Connection getConnection(){
//调用getFreeConnection获取连接
ConnectionObject connectionobj = getFreeConnection();
//若没有空闭连接并且连接池没有达到上限,创建一个新连接
if(connectionobj == null && pool.size() < connectionPoolMaxSize){
ConnectionObject co = new ConnectionObject(url, username,password);
pool.addElement(co);
connectionobj = getFreeConnection();
}
//将连接对象的状态设为忙,并把物理连接返回给用户,否则进入等待状态
if(connectionobj != null){
connectionobj.setIsUse(true);
connectionobj.addUseCount();
return connectionobj.getConnection();
}
else{
//等待timeout时间
try{
java.lang.Thread.sleep(timeout);
}
catch(Exception e){
System.err.print(e.getMessage());
}
connectionobj = getFreeConnection();
if(connectionobj != null){
connectionobj.setIsUse(true);
connectionobj.addUseCount();
return connectionobj.getConnection();
}
return null;
}
}
}
数据库配置文件dbconfig.txt(以MySql数据库为例)内容如下:
# 数据库连接池配置文件
# 数据库驱动程序
db.driver=org.gjt.mm.mysql.Driver
# 数据库url(server:数据库服务器名或IP dsp:数据库)
db.url=jdbc:mysql://server:3306/dsp?useUnicode=true&characterEncoding=GBK
# 数据库用户名
db.user=root
# 数据库用户密码
db.password=123456
# 最小连接数
db.minconnection=10
# 最大连接数(连接池上限)
db.maxconnection=20
#每个连接最大使用次数
db.connectionmaxusecount=100
#设置连接超时时间,单位毫秒
db.timeout = 50000;
只要修改数据库配置文件(dbconfig.txt)中的相关连接信息,就可以很简单的与其它数据库进行连接。
4组件的使用
本组件接口简单,使用方便,用法如下四个步骤:
① 数据库配置文件(dbconfig.txt)进行数据库连接配置;
② 入组件包类,即:
import com.db.*;
③ 创建一个静态的连接池变量,即:
private static ConnectionPool cp = new ConnectionPool();
④ 连接的获取,直接调用ConnectionPool类的getConnection()方法,如:
Connection conn = cp.getConnection();
释放连接,直接调用ConnectionPool类的realse()方法,如:
cp.realse(conn);
总之,使用连接池技术可以很好的改善大量联机并行访问的应用系统中数据库访问速度的瓶颈,大大地提高系统效率,因此我们把数据库连接池做成组件方便构建高性能的数据库应用。
--------------------------------------------------------------------------------
java数据库连接池(参考)
最新推荐文章于 2025-05-26 15:06:19 发布