• 用java实现JDBC数据库连接池


      这次写数据库连接池主要想解决的还是servlet访问数据库获取数据的稳定性问题,于是便研究了一下,下面来讲一讲如何用java来写一个适合自己用的数据库连接池。这个东西大家并不陌生,通过使用数据连接池我们能够更好地控制程序和数据库之间建立的连接,减小数据库访问压力,也便于管理连接,提高了利用率和工作性能。

      设计数据库连接池,个人认为应该注意以下几点:

      1、能够控制连接池的大小

      2、有一个统一的接口用于获得连接

      3、使用后的连接要有一个接口能够接受并处理掉

      4、连接池要有自我维护能力,比如说暂时提高连接池大小以应对可能的连接小高潮,或者处理多余的连接

      ok,我们先确定连接池的数据结构:

     1 public class SimpleConnetionPool {
     2     private static LinkedList m_notUsedConnection = new LinkedList();
     3     private static HashSet m_usedUsedConnection = new HashSet();
     4     private static String m_url = "";
     5     private static String m_user = "";
     6     private static String m_password = "";
     7     private static int m_maxConnect = 3;
     8     static final boolean DEBUG = false;
     9     static private long m_lastClearClosedConnection = System
    10             .currentTimeMillis();
    11     public static long CHECK_CLOSED_CONNECTION_TIME = 5000; // 5秒
    12 }

      

      然后我们看看数据库连接池的核心部分,首先是清除连接池中多余的连接。我们每隔一段时间就对连接池中的所有连接进行检查,第一轮循环判断这些链接是否已经关闭,如果关闭了则直接移除它们,第二轮循环则是根据目前规定的最大数量裁撤空闲连接。

     1 private static void clearClosedConnection() {
     2         long time = System.currentTimeMillis();
     3 
     4         // 时间不合理,没有必要检查
     5         if (time < m_lastClearClosedConnection) {
     6             time = m_lastClearClosedConnection;
     7             return;
     8         }
     9 
    10         // 时间太短,没有必要检查
    11         if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {
    12             return;
    13         }
    14 
    15         m_lastClearClosedConnection = time;
    16 
    17         // 开始检查没有使用的Connection
    18         Iterator iterator = m_notUsedConnection.iterator();
    19         while (iterator.hasNext()) {
    20             Connection con = (Connection) iterator.next();
    21 
    22             try {
    23                 if (con.isClosed()) {
    24                     iterator.remove();
    25                 }
    26             } catch (SQLException e) {
    27                 iterator.remove();
    28 
    29                 if (DEBUG) {
    30                     System.out.println("问题连接已断开");
    31                 }
    32             }
    33         }
    34 
    35         // 清除多余的Connection
    36         int decrease = getDecreasingConnectionCount();
    37 
    38         while (decrease > 0 && m_notUsedConnection.size() > 0) {
    39             Connection con = (Connection) m_notUsedConnection.removeFirst();
    40 
    41             try {
    42                 con.close();
    43             } catch (SQLException e) {
    44 
    45             }
    46 
    47             decrease--;
    48         }
    49     }

      

      接下来我们看一下申请一个新的连接是如何进行的,首先我们先调用之前的清理器来清除多余的连接和无法使用的连接,之后在空闲连接中寻找是否有可是的连接,如果有符合的则直接分配出去,但是要是没找到的话该怎么办呢?

      这时候我们就需要建立新的连接来提供了,建立新的连接后我们将其中一个分配出去,剩下的加入到空闲连接中去等待分配就可以了。

     1 public static synchronized Connection getConnection() {
     2         // 关闭清除多余的连接
     3         clearClosedConnection();
     4 
     5         // 输出当前总连接数
     6         if(DEBUG)
     7             System.out.println("当前总连接数:" + getConnectionCount());
     8 
     9         // 寻找空闲的连接
    10         while (m_notUsedConnection.size() > 0) {
    11             try {
    12                 Connection con = (Connection) m_notUsedConnection.removeFirst();
    13 
    14                 if (con.isClosed()) {
    15                     continue;
    16                 }
    17 
    18                 m_usedUsedConnection.add(con);
    19                 if (DEBUG) {
    20                     // System.out.println("连接初始化成功");
    21                 }
    22                 return con;
    23             } catch (SQLException e) {
    24             }
    25         }
    26 
    27         // 没有找到,建立一些新的连接以供使用
    28         int newCount = getIncreasingConnectionCount();
    29         LinkedList list = new LinkedList();
    30         Connection con = null;
    31 
    32         for (int i = 0; i < newCount; i++) {
    33             con = getNewConnection();
    34             if (con != null) {
    35                 list.add(con);
    36             }
    37         }
    38 
    39         // 没有成功建立连接,访问失败
    40         if (list.size() == 0)
    41             return null;
    42 
    43         // 成功建立连接,使用的加入used队列,剩下的加入notUsed队列
    44         con = (Connection) list.removeFirst();
    45         m_usedUsedConnection.add(con);
    46         m_notUsedConnection.addAll(list);
    47         list.clear();
    48 
    49         return con;
    50     }

      根据之前总结的我们还需要一个,就是交还连接了,这个很简单,把占用中的链接移出来放到空闲连接里就可以了~很简单吧~

    1 static synchronized void pushConnectionBackToPool(Connection con) {
    2         boolean exist = m_usedUsedConnection.remove(con);
    3         if (exist) {
    4             m_notUsedConnection.addLast(con);
    5         }
    6     }

      

      这就是这个数据连接池的核心部分了,现在我们来看整套代码就容易多了,其实需要注意的就是刚才说的那些:

      1 package cn.com.css.cas.jdbc;
      2 
      3 import java.sql.Connection;
      4 import java.sql.Driver;
      5 import java.sql.DriverManager;
      6 import java.sql.SQLException;
      7 import java.util.HashSet;
      8 import java.util.Iterator;
      9 import java.util.LinkedList;
     10 
     11 /**
     12  * JDBC数据库连接池
     13  * 
     14  * @author Woud
     15  * 
     16  */
     17 public class SimpleConnetionPool {
     18     private static LinkedList m_notUsedConnection = new LinkedList();
     19     private static HashSet m_usedUsedConnection = new HashSet();
     20     private static String m_url = "";
     21     private static String m_user = "";
     22     private static String m_password = "";
     23     private static int m_maxConnect = 3;
     24     static final boolean DEBUG = false;
     25     static private long m_lastClearClosedConnection = System
     26             .currentTimeMillis();
     27     public static long CHECK_CLOSED_CONNECTION_TIME = 5000; // 5秒
     28 
     29     static {
     30         try {
     31             initDriver();
     32         } catch (InstantiationException e) {
     33             // TODO Auto-generated catch block
     34             e.printStackTrace();
     35         } catch (IllegalAccessException e) {
     36             // TODO Auto-generated catch block
     37             e.printStackTrace();
     38         } catch (ClassNotFoundException e) {
     39             // TODO Auto-generated catch block
     40             e.printStackTrace();
     41         }
     42     }
     43 
     44     public SimpleConnetionPool(String url, String user, String password) {
     45         m_url = url;
     46         m_user = user;
     47         m_password = password;
     48     }
     49 
     50     private static void initDriver() throws InstantiationException,
     51             IllegalAccessException, ClassNotFoundException {
     52         Driver driver = null;
     53 
     54         // 读取MySql的Driver
     55         driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();
     56         installDriver(driver);
     57 
     58         /*
     59          * // 读取postgresql的driver driver = (Driver)
     60          * Class.forName("org.postgresql.Driver").newInstance();
     61          * installDriver(driver);
     62          */
     63 
     64     }
     65 
     66     public static void installDriver(Driver driver) {
     67         try {
     68             DriverManager.registerDriver(driver);
     69         } catch (SQLException e) {
     70             // TODO Auto-generated catch block
     71             e.printStackTrace();
     72         }
     73     }
     74 
     75     public static synchronized Connection getConnection() {
     76         // 关闭清除多余的连接
     77         clearClosedConnection();
     78 
     79         // 输出当前总连接数
     80         if(DEBUG)
     81             System.out.println("当前总连接数:" + getConnectionCount());
     82 
     83         // 寻找空闲的连接
     84         while (m_notUsedConnection.size() > 0) {
     85             try {
     86                 Connection con = (Connection) m_notUsedConnection.removeFirst();
     87 
     88                 if (con.isClosed()) {
     89                     continue;
     90                 }
     91 
     92                 m_usedUsedConnection.add(con);
     93                 if (DEBUG) {
     94                     // System.out.println("连接初始化成功");
     95                 }
     96                 return con;
     97             } catch (SQLException e) {
     98             }
     99         }
    100 
    101         // 没有找到,建立一些新的连接以供使用
    102         int newCount = getIncreasingConnectionCount();
    103         LinkedList list = new LinkedList();
    104         Connection con = null;
    105 
    106         for (int i = 0; i < newCount; i++) {
    107             con = getNewConnection();
    108             if (con != null) {
    109                 list.add(con);
    110             }
    111         }
    112 
    113         // 没有成功建立连接,访问失败
    114         if (list.size() == 0)
    115             return null;
    116 
    117         // 成功建立连接,使用的加入used队列,剩下的加入notUsed队列
    118         con = (Connection) list.removeFirst();
    119         m_usedUsedConnection.add(con);
    120         m_notUsedConnection.addAll(list);
    121         list.clear();
    122 
    123         return con;
    124     }
    125 
    126     public static Connection getNewConnection() {
    127         try {
    128             Connection con = DriverManager.getConnection(m_url, m_user,
    129                     m_password);
    130             return con;
    131         } catch (SQLException e) {
    132             // TODO Auto-generated catch block
    133             e.printStackTrace();
    134         }
    135 
    136         return null;
    137     }
    138 
    139     static synchronized void pushConnectionBackToPool(Connection con) {
    140         boolean exist = m_usedUsedConnection.remove(con);
    141         if (exist) {
    142             m_notUsedConnection.addLast(con);
    143         }
    144     }
    145 
    146     public static int close() {
    147         int count = 0;
    148 
    149         Iterator iterator = m_notUsedConnection.iterator();
    150         while (iterator.hasNext()) {
    151             try {
    152                 ((Connection) iterator.next()).close();
    153                 count++;
    154             } catch (SQLException e) {
    155                 // TODO Auto-generated catch block
    156                 e.printStackTrace();
    157             }
    158         }
    159         m_notUsedConnection.clear();
    160 
    161         iterator = m_usedUsedConnection.iterator();
    162         while (iterator.hasNext()) {
    163             try {
    164                 ((Connection) iterator.next()).close();
    165             } catch (SQLException e) {
    166                 // TODO Auto-generated catch block
    167                 e.printStackTrace();
    168             }
    169         }
    170         m_usedUsedConnection.clear();
    171 
    172         return count;
    173     }
    174 
    175     private static void clearClosedConnection() {
    176         long time = System.currentTimeMillis();
    177 
    178         // 时间不合理,没有必要检查
    179         if (time < m_lastClearClosedConnection) {
    180             time = m_lastClearClosedConnection;
    181             return;
    182         }
    183 
    184         // 时间太短,没有必要检查
    185         if (time - m_lastClearClosedConnection < CHECK_CLOSED_CONNECTION_TIME) {
    186             return;
    187         }
    188 
    189         m_lastClearClosedConnection = time;
    190 
    191         // 开始检查没有使用的Connection
    192         Iterator iterator = m_notUsedConnection.iterator();
    193         while (iterator.hasNext()) {
    194             Connection con = (Connection) iterator.next();
    195 
    196             try {
    197                 if (con.isClosed()) {
    198                     iterator.remove();
    199                 }
    200             } catch (SQLException e) {
    201                 iterator.remove();
    202 
    203                 if (DEBUG) {
    204                     System.out.println("问题连接已断开");
    205                 }
    206             }
    207         }
    208 
    209         // 清除多余的Connection
    210         int decrease = getDecreasingConnectionCount();
    211 
    212         while (decrease > 0 && m_notUsedConnection.size() > 0) {
    213             Connection con = (Connection) m_notUsedConnection.removeFirst();
    214 
    215             try {
    216                 con.close();
    217             } catch (SQLException e) {
    218 
    219             }
    220 
    221             decrease--;
    222         }
    223     }
    224 
    225     public static int getIncreasingConnectionCount() {
    226         int count = 1;
    227         count = getConnectionCount() / 4;
    228 
    229         if (count < 1)
    230             count = 1;
    231 
    232         return count;
    233     }
    234 
    235     public static int getDecreasingConnectionCount() {
    236         int count = 0;
    237 
    238         if (getConnectionCount() > m_maxConnect) {
    239             count = getConnectionCount() - m_maxConnect;
    240         }
    241 
    242         return count;
    243     }
    244 
    245     public static synchronized int getNotUsedConnectionCount() {
    246         return m_notUsedConnection.size();
    247     }
    248 
    249     public static synchronized int getUsedConnectionCount() {
    250         return m_usedUsedConnection.size();
    251     }
    252 
    253     public static synchronized int getConnectionCount() {
    254         return m_notUsedConnection.size() + m_usedUsedConnection.size();
    255     }
    256 
    257 }

     我们做好了这个连接池之后怎么用呢,这很简单,我们用Singleton模式做一个连接池管理器,然后对接口进行简单的封装后就可以进行使用了,管理器调用连接池的getconnection接口获得connect后和数据库建立连接,运行sql后交还connect并把结果反馈回来就可以了。

  • 相关阅读:
    验证码
    Linux 常用命令
    WTM_LayUI 二级联动
    文件上传漏洞及绕过
    Web For Pentester靶场(xss部分)
    文件上传漏洞fuzz字典生成脚本小工具分享
    两种搭建个人博客方法
    DVWA(xss部分源码分析)
    xss小游戏源码分析
    linux下启动tomcat报错:The BASEDIR environment...
  • 原文地址:https://www.cnblogs.com/woud/p/3031439.html
Copyright © 2020-2023  润新知