分享
 
 
 

Java 的JDBC 数据库连接池实现方法

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Java 的JDBC 数据库连接池实现方法

关键字: Java, JDBC, Connection Pool, Database, 数据库连接池, sourcecode

虽然 J2EE 程序员一般都有现成的应用服务器所带的JDBC 数据库连接池,不过对于开发一般的 Java Application 、 Applet 或者 JSP、velocity 时,我们可用的JDBC 数据库连接池并不多,并且一般性能都不好。 Java 程序员都很羡慕 Windows ADO ,只需要 new Connection 就可以直接从数据库连接池中返回 Connection。并且 ADO Connection 是线程安全的,多个线程可以共用一个 Connection, 所以 ASP 程序一般都把 getConnection 放在 Global.asa 文件中,在 IIS 启动时建立数据库连接。ADO 的 Connection 和 Result 都有很好的缓冲,并且很容易使用。

其实我们可以自己写一个JDBC 数据库连接池。写 JDBC connection pool 的注意事项有:

1. 有一个简单的函数从连接池中得到一个 Connection。

2. close 函数必须将 connection 放回 数据库连接池。

3. 当数据库连接池中没有空闲的 connection, 数据库连接池必须能够自动增加 connection 个数。

4. 当数据库连接池中的 connection 个数在某一个特别的时间变得很大,但是以后很长时间只用其中一小部分,应该可以自动将多余的 connection 关闭掉。

5. 如果可能,应该提供debug 信息报告没有关闭的 new Connection 。

如果要 new Connection 就可以直接从数据库连接池中返回 Connection, 可以这样写( Mediator pattern ) (以下代码中使用了中文全角空格):

public class EasyConnection implements java.sql.Connection{

private Connection m_delegate = null;

public EasyConnection(){

m_delegate = getConnectionFromPool();

}

public void close(){

putConnectionBackToPool(m_delegate);

}

public PreparedStatement prepareStatement(String sql) throws SQLException{

m_delegate.prepareStatement(sql);

}

//...... other method

}

看来并不难。不过不建议这种写法,因为应该尽量避免使用 Java Interface, 关于 Java Interface 的缺点我另外再写文章讨论。大家关注的是 Connection Pool 的实现方法。下面给出一种实现方法。

import java.sql.*;

import java.lang.reflect.*;

import java.util.*;

import java.io.*;

public class SimpleConnetionPool {

private static LinkedList m_notUsedConnection = new LinkedList();

private static HashSet m_usedUsedConnection = new HashSet();

private static String m_url = "";

private static String m_user = "";

private static String m_password = "";

static final boolean DEBUG = true;

static private long m_lastClearClosedConnection = System.currentTimeMillis();

public static long CHECK_CLOSED_CONNECTION_TIME = 4 * 60 * 60 * 1000; //4 hours

static {

initDriver();

}

private SimpleConnetionPool() {

}

private static void initDriver() {

Driver driver = null;

//load mysql driver

try {

driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();

installDriver(driver);

} catch (Exception e) {

}

//load postgresql driver

try {

driver = (Driver) Class.forName("org.postgresql.Driver").newInstance();

installDriver(driver);

} catch (Exception e) {

}

}

public static void installDriver(Driver driver) {

try {

DriverManager.registerDriver(driver);

} catch (Exception e) {

e.printStackTrace();

}

}

public static synchronized Connection getConnection() {

clearClosedConnection();

while (m_notUsedConnection.size() > 0) {

try {

ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection.removeFirst();

if (wrapper.connection.isClosed()) {

continue;

}

m_usedUsedConnection.add(wrapper);

if (DEBUG) {

wrapper.debugInfo = new Throwable("Connection initial statement");

}

return wrapper.connection;

} catch (Exception e) {

}

}

int newCount = getIncreasingConnectionCount();

LinkedList list = new LinkedList();

ConnectionWrapper wrapper = null;

for (int i = 0; i < newCount; i++) {

wrapper = getNewConnection();

if (wrapper != null) {

list.add(wrapper);

}

}

if (list.size() == 0) {

return null;

}

wrapper = (ConnectionWrapper) list.removeFirst();

m_usedUsedConnection.add(wrapper);

m_notUsedConnection.addAll(list);

list.clear();

return wrapper.connection;

}

private static ConnectionWrapper getNewConnection() {

try {

Connection con = DriverManager.getConnection(m_url, m_user, m_password);

ConnectionWrapper wrapper = new ConnectionWrapper(con);

return wrapper;

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

static synchronized void pushConnectionBackToPool(ConnectionWrapper con) {

boolean exist = m_usedUsedConnection.remove(con);

if (exist) {

m_notUsedConnection.addLast(con);

}

}

public static int close() {

int count = 0;

Iterator iterator = m_notUsedConnection.iterator();

while (iterator.hasNext()) {

try {

( (ConnectionWrapper) iterator.next()).close();

count++;

} catch (Exception e) {

}

}

m_notUsedConnection.clear();

iterator = m_usedUsedConnection.iterator();

while (iterator.hasNext()) {

try {

ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();

wrapper.close();

if (DEBUG) {

wrapper.debugInfo.printStackTrace();

}

count++;

} catch (Exception e) {

}

}

m_usedUsedConnection.clear();

return count;

}

private static void clearClosedConnection() {

long time = System.currentTimeMillis();

//sometimes user change system time,just return

if (time < m_lastClearClosedConnection) {

time = m_lastClearClosedConnection;

return;

}

//no need check very often

if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {

return;

}

m_lastClearClosedConnection = time;

//begin check

Iterator iterator = m_notUsedConnection.iterator();

while (iterator.hasNext()) {

ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();

try {

if (wrapper.connection.isClosed()) {

iterator.remove();

}

} catch (Exception e) {

iterator.remove();

if (DEBUG) {

System.out.println("connection is closed, this connection initial StackTrace");

wrapper.debugInfo.printStackTrace();

}

}

}

//make connection pool size smaller if too big

int decrease = getDecreasingConnectionCount();

if (m_notUsedConnection.size() < decrease) {

return;

}

while (decrease-- > 0) {

ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection.removeFirst();

try {

wrapper.connection.close();

} catch (Exception e) {

}

}

}

/**

* get increasing connection count, not just add 1 connection

* @return count

*/

public static int getIncreasingConnectionCount() {

int count = 1;

int current = getConnectionCount();

count = current / 4;

if (count < 1) {

count = 1;

}

return count;

}

/**

* get decreasing connection count, not just remove 1 connection

* @return count

*/

public static int getDecreasingConnectionCount() {

int count = 0;

int current = getConnectionCount();

if (current < 10) {

return 0;

}

return current / 3;

}

public synchronized static void printDebugMsg() {

printDebugMsg(System.out);

}

public synchronized static void printDebugMsg(PrintStream out) {

if (DEBUG == false) {

return;

}

StringBuffer msg = new StringBuffer();

msg.append("debug message in " + SimpleConnetionPool.class.getName());

msg.append("\r\n");

msg.append("total count is connection pool: " + getConnectionCount());

msg.append("\r\n");

msg.append("not used connection count: " + getNotUsedConnectionCount());

msg.append("\r\n");

msg.append("used connection, count: " + getUsedConnectionCount());

out.println(msg);

Iterator iterator = m_usedUsedConnection.iterator();

while (iterator.hasNext()) {

ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();

wrapper.debugInfo.printStackTrace(out);

}

out.println();

}

public static synchronized int getNotUsedConnectionCount() {

return m_notUsedConnection.size();

}

public static synchronized int getUsedConnectionCount() {

return m_usedUsedConnection.size();

}

public static synchronized int getConnectionCount() {

return m_notUsedConnection.size() + m_usedUsedConnection.size();

}

public static String getUrl() {

return m_url;

}

public static void setUrl(String url) {

if (url == null) {

return;

}

m_url = url.trim();

}

public static String getUser() {

return m_user;

}

public static void setUser(String user) {

if (user == null) {

return;

}

m_user = user.trim();

}

public static String getPassword() {

return m_password;

}

public static void setPassword(String password) {

if (password == null) {

return;

}

m_password = password.trim();

}

}

class ConnectionWrapper implements InvocationHandler {

private final static String CLOSE_METHOD_NAME = "close";

public Connection connection = null;

private Connection m_originConnection = null;

public long lastAccessTime = System.currentTimeMillis();

Throwable debugInfo = new Throwable("Connection initial statement");

ConnectionWrapper(Connection con) {

Class[] interfaces = {java.sql.Connection.class};

this.connection = (Connection) Proxy.newProxyInstance(

con.getClass().getClassLoader(),

interfaces, this);

m_originConnection = con;

}

void close() throws SQLException {

m_originConnection.close();

}

public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {

Object obj = null;

if (CLOSE_METHOD_NAME.equals(m.getName())) {

SimpleConnetionPool.pushConnectionBackToPool(this);

}

else {

obj = m.invoke(m_originConnection, args);

}

lastAccessTime = System.currentTimeMillis();

return obj;

}

}

使用方法

public class TestConnectionPool{

public static void main(String[] args) {

SimpleConnetionPool.setUrl(DBTools.getDatabaseUrl());

SimpleConnetionPool.setUser(DBTools.getDatabaseUserName());

SimpleConnetionPool.setPassword(DBTools.getDatabasePassword());

Connection con = SimpleConnetionPool.getConnection();

Connection con1 = SimpleConnetionPool.getConnection();

Connection con2 = SimpleConnetionPool.getConnection();

//do something with con ...

try {

con.close();

} catch (Exception e) {}

try {

con1.close();

} catch (Exception e) {}

try {

con2.close();

} catch (Exception e) {}

con = SimpleConnetionPool.getConnection();

con1 = SimpleConnetionPool.getConnection();

try {

con1.close();

} catch (Exception e) {}

con2 = SimpleConnetionPool.getConnection();

SimpleConnetionPool.printDebugMsg();

}

}

运行测试程序后打印连接池中 Connection 状态, 以及正在使用的没有关闭 Connection 信息。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有