java數據庫連接池(參考)
以文本方式查看主題
- 太廣軟件技術論壇 (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);
總之,使用連接池技術可以很好的改善大量聯機並行訪問的應用系統中數據庫訪問速度的瓶頸,大大地提高系統效率,因此我們把數據庫連接池做成組件方便構建高性能的數據庫應用。
--------------------------------------------------------------------------------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.