博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java之中JDBC数据库连接池实现方法
阅读量:6428 次
发布时间:2019-06-23

本文共 9005 字,大约阅读时间需要 30 分钟。

hot3.png

 

作为一名初级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) {   this.connection = (Connection) Proxy.newProxyInstance(   con.getClass().getClassLoader(),   con.getClass().getInterfaces(), 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();     }   最后一点就是
运行测试程序后打印JDBC数据库连接池中Connection状态,以及正在使用的没有关闭Connection信息。

end,动手练习一下。

转载于:https://my.oschina.net/bigfool007139/blog/495546

你可能感兴趣的文章
谈谈fail-fast与fail-safe是什么以及工作机制
查看>>
一个滑动特效
查看>>
深入浅出换肤相关技术以及如何实现
查看>>
Redis 基础、高级特性与性能调优
查看>>
React native 第三方组件 React native swiper
查看>>
接口幂等设计
查看>>
编程入门指南
查看>>
移动端的自适应方案—REM
查看>>
你真的懂volatile吗
查看>>
Android 编译时注解-提升
查看>>
说说 Spring AOP 中 @Aspect 的高级用法
查看>>
Workbox CLI中文版
查看>>
贝聊亿级数据库分库分表实践
查看>>
同时连接gitlab和github
查看>>
vuex源码分析
查看>>
二叉树操作(面试必备)
查看>>
Fiddler简单使用
查看>>
$.data()和$().data()
查看>>
一个逻辑清晰的购物车模型
查看>>
php通过共享内存,控制mysql连接数,多进程插入数据(pcnt学习四)
查看>>