zoukankan      html  css  js  c++  java
  • java实现数据库连接池

    1. package com.kyo.connection;  
    2.   
    3. import java.sql.Connection;  
    4. import java.sql.DatabaseMetaData;  
    5. import java.sql.Driver;  
    6. import java.sql.DriverManager;  
    7. import java.sql.SQLException;  
    8. import java.sql.Statement;  
    9. import java.util.Enumeration;  
    10. import java.util.Vector;  
    11.   
    12. public class ConnectionPool {  
    13.   
    14.     private ConnectionParam param;  
    15.   
    16.     private String testTable = ""; // 测试连接是否可用的测试表名,默认没有测试表  
    17.   
    18.     private Vector connections = null; // 存放连接池中数据库连接的向量 , 初始时为  
    19.                                         // null,它中存放的对象为PooledConnection 型  
    20.   
    21.     public void setParam(ConnectionParam param) {  
    22.         this.param = param;  
    23.     }  
    24.   
    25.     public ConnectionParam getParam() {  
    26.         return param;  
    27.     }  
    28.   
    29.     /** 
    30.      * 构造函数 
    31.      *  
    32.      * @param param 
    33.      */  
    34.     public ConnectionPool(ConnectionParam param) {  
    35.         this.param = param;  
    36.     }  
    37.   
    38.     /** 
    39.      *  
    40.      * 获取测试数据库表的名字 
    41.      *  
    42.      * @return 测试数据库表的名字 
    43.      */  
    44.   
    45.     public String getTestTable() {  
    46.         return this.testTable;  
    47.     }  
    48.   
    49.     /** 
    50.      *  
    51.      * 设置测试表的名字 
    52.      *  
    53.      * @param testTable 
    54.      *            String 测试表的名字 
    55.      */  
    56.   
    57.     public void setTestTable(String testTable) {  
    58.         this.testTable = testTable;  
    59.     }  
    60.   
    61.     /** 
    62.      * 创建一个数据库连接池,连接池中的可用连接的数量采用类成员 initialConnections 中设置的值 
    63.      */  
    64.   
    65.     public synchronized void createPool() throws Exception {  
    66.   
    67.         // 确保连接池没有创建  
    68.         // 如果连接池己经创建了,保存连接的向量 connections 不会为空  
    69.         if (connections != null) {  
    70.             return; // 如果己经创建,则返回  
    71.         }  
    72.   
    73.         // 实例化 JDBC Driver 中指定的驱动类实例  
    74.         Driver driver = (Driver) (Class.forName(this.param.getDriver())  
    75.                 .newInstance());  
    76.         DriverManager.registerDriver(driver); // 注册 JDBC 驱动程序  
    77.         // 创建保存连接的向量 , 初始时有 0 个元素  
    78.         connections = new Vector();  
    79.   
    80.         // 根据 initialConnections 中设置的值,创建连接。  
    81.         createConnections(this.param.getMinConnection());  
    82.         System.out.println(" 数据库连接池创建成功! ");  
    83.   
    84.     }  
    85.   
    86.     /** 
    87.      *  
    88.      * 创建由 numConnections 指定数目的数据库连接 , 并把这些连接 放入 connections 向量中 
    89.      *  
    90.      * @param numConnections 
    91.      *            要创建的数据库连接的数目 
    92.      */  
    93.   
    94.     private void createConnections(int numConnections) throws SQLException {  
    95.   
    96.         // 循环创建指定数目的数据库连接  
    97.         for (int x = 0; x < numConnections; x++) {  
    98.             // 是否连接池中的数据库连接的数量己经达到最大?最大值由类成员 maxConnections,指出,如果 maxConnections  
    99.             // 为 0 或负数,表示连接数量没有限制。  
    100.             // 如果连接数己经达到最大,即退出。  
    101.   
    102.             if (this.param.getMaxConnection() > 0  
    103.                     && this.connections.size() >= this.param.getMaxConnection()) {  
    104.                 break;  
    105.             }  
    106.   
    107.             // add a new PooledConnection object to connections vector  
    108.             // 增加一个连接到连接池中(向量 connections 中)  
    109.             try {  
    110.                 connections.addElement(new PooledConnection(newConnection()));  
    111.             } catch (SQLException e) {  
    112.                 System.out.println(" 创建数据库连接失败! " + e.getMessage());  
    113.                 throw new SQLException();  
    114.             }  
    115.   
    116.             System.out.println(" 数据库连接己创建 ......");  
    117.         }  
    118.   
    119.     }  
    120.   
    121.     /** 
    122.      *  
    123.      * 创建一个新的数据库连接并返回它 
    124.      *  
    125.      * @return 返回一个新创建的数据库连接 
    126.      */  
    127.   
    128.     private Connection newConnection() throws SQLException {  
    129.   
    130.         // 创建一个数据库连接  
    131.         Connection conn = DriverManager.getConnection(this.param.getUrl(),  
    132.                 this.param.getUser(), this.param.getPassword());  
    133.   
    134.         // 如果这是第一次创建数据库连接,即检查数据库,获得此数据库允许支持的  
    135.         // 最大客户连接数目  
    136.         // connections.size()==0 表示目前没有连接己被创建  
    137.   
    138.         if (connections.size() == 0) {  
    139.   
    140.             DatabaseMetaData metaData = conn.getMetaData();  
    141.             int driverMaxConnections = metaData.getMaxConnections();  
    142.   
    143.             // 数据库返回的 driverMaxConnections 若为 0 ,表示此数据库没有最大  
    144.             // 连接限制,或数据库的最大连接限制不知道  
    145.             // driverMaxConnections 为返回的一个整数,表示此数据库允许客户连接的数 目  
    146.             // 如果连接池中设置的最大连接数量大于数据库允许的连接数目 , 则置连接池 的最大  
    147.             // 连接数目为数据库允许的最大数目  
    148.   
    149.             if (driverMaxConnections > 0  
    150.                     && this.param.getMaxConnection() > driverMaxConnections) {  
    151.                 this.param.setMaxConnection(driverMaxConnections);  
    152.             }  
    153.         }  
    154.         return conn; // 返回创建的新的数据库连接  
    155.     }  
    156.   
    157.     /** 
    158.      *  
    159.      * 通过调用 getFreeConnection() 函数返回一个可用的数据库连接 , 
    160.      *  
    161.      * 如果当前没有可用的数据库连接,并且更多的数据库连接不能创 
    162.      *  
    163.      * 建(如连接池大小的限制),此函数等待一会再尝试获取。 
    164.      *  
    165.      * @return 返回一个可用的数据库连接对象 
    166.      */  
    167.   
    168.     public synchronized Connection getConnection() throws SQLException {  
    169.   
    170.         // 确保连接池己被创建  
    171.         if (connections == null) {  
    172.             return null; // 连接池还没创建,则返回 null  
    173.         }  
    174.   
    175.         Connection conn = getFreeConnection(); // 获得一个可用的数据库连接  
    176.         // 如果目前没有可以使用的连接,即所有的连接都在使用中  
    177.   
    178.         while (conn == null) {  
    179.             // 等一会再试  
    180.             wait(250);  
    181.             conn = getFreeConnection(); // 重新再试,直到获得可用的连接,如果  
    182.             // getFreeConnection() 返回的为 null  
    183.             // 则表明创建一批连接后也不可获得可用连接  
    184.         }  
    185.   
    186.         return conn;// 返回获得的可用的连接  
    187.     }  
    188.   
    189.     /** 
    190.      *  
    191.      * 本函数从连接池向量 connections 中返回一个可用的的数据库连接,如果 
    192.      *  
    193.      * 当前没有可用的数据库连接,本函数则根据 incrementalConnections 设置 
    194.      *  
    195.      * 的值创建几个数据库连接,并放入连接池中。 
    196.      *  
    197.      * 如果创建后,所有的连接仍都在使用中,则返回 null 
    198.      *  
    199.      * @return 返回一个可用的数据库连接 
    200.      */  
    201.   
    202.     private Connection getFreeConnection() throws SQLException {  
    203.   
    204.         // 从连接池中获得一个可用的数据库连接  
    205.         Connection conn = findFreeConnection();  
    206.         if (conn == null) {  
    207.             // 如果目前连接池中没有可用的连接  
    208.             // 创建一些连接  
    209.             createConnections(this.param.getIncrementalConnections());  
    210.             // 重新从池中查找是否有可用连接  
    211.             conn = findFreeConnection();  
    212.             if (conn == null) {  
    213.                 // 如果创建连接后仍获得不到可用的连接,则返回 null  
    214.                 return null;  
    215.             }  
    216.         }  
    217.         return conn;  
    218.   
    219.     }  
    220.   
    221.     /** 
    222.      *  
    223.      * 查找连接池中所有的连接,查找一个可用的数据库连接, 
    224.      *  
    225.      * 如果没有可用的连接,返回 null 
    226.      *  
    227.      * @return 返回一个可用的数据库连接 
    228.      */  
    229.   
    230.     private Connection findFreeConnection() throws SQLException {  
    231.   
    232.         Connection conn = null;  
    233.         PooledConnection pConn = null;  
    234.         // 获得连接池向量中所有的对象  
    235.         Enumeration enumerate = connections.elements();  
    236.         // 遍历所有的对象,看是否有可用的连接  
    237.         while (enumerate.hasMoreElements()) {  
    238.             pConn = (PooledConnection) enumerate.nextElement();  
    239.             if (!pConn.isBusy()) {  
    240.                 // 如果此对象不忙,则获得它的数据库连接并把它设为忙  
    241.                 conn = pConn.getConnection();  
    242.                 pConn.setBusy(true);  
    243.                 // 测试此连接是否可用  
    244.                 if (!testConnection(conn)) {  
    245.                     // 如果此连接不可再用了,则创建一个新的连接,  
    246.                     // 并替换此不可用的连接对象,如果创建失败,返回 null  
    247.                     try {  
    248.                         conn = newConnection();  
    249.                     } catch (SQLException e) {  
    250.                         System.out.println(" 创建数据库连接失败! " + e.getMessage());  
    251.                         return null;  
    252.                     }  
    253.                     pConn.setConnection(conn);  
    254.                 }  
    255.                 break; // 己经找到一个可用的连接,退出  
    256.             }  
    257.         }  
    258.   
    259.         return conn;// 返回找到到的可用连接  
    260.   
    261.     }  
    262.   
    263.     /** 
    264.      *  
    265.      * 测试一个连接是否可用,如果不可用,关掉它并返回 false 
    266.      *  
    267.      * 否则可用返回 true 
    268.      *  
    269.      *  
    270.      *  
    271.      * @param conn 
    272.      *            需要测试的数据库连接 
    273.      *  
    274.      * @return 返回 true 表示此连接可用, false 表示不可用 
    275.      */  
    276.   
    277.     private boolean testConnection(Connection conn) {  
    278.   
    279.         try {  
    280.   
    281.             // 判断测试表是否存在  
    282.             if (testTable.equals("")) {  
    283.                 // 如果测试表为空,试着使用此连接的 setAutoCommit() 方法  
    284.                 // 来判断连接否可用(此方法只在部分数据库可用,如果不可用 ,  
    285.                 // 抛出异常)。注意:使用测试表的方法更可靠  
    286.                 conn.setAutoCommit(true);  
    287.             } else {  
    288.                 // 有测试表的时候使用测试表测试  
    289.                 // check if this connection is valid  
    290.                 Statement stmt = conn.createStatement();  
    291.                 stmt.execute("select count(*) from " + testTable);  
    292.             }  
    293.   
    294.         } catch (SQLException e) {  
    295.             // 上面抛出异常,此连接己不可用,关闭它,并返回 false;  
    296.             closeConnection(conn);  
    297.             return false;  
    298.         }  
    299.         // 连接可用,返回 true  
    300.         return true;  
    301.   
    302.     }  
    303.   
    304.     /** 
    305.      *  
    306.      * 此函数返回一个数据库连接到连接池中,并把此连接置为空闲。 
    307.      *  
    308.      * 所有使用连接池获得的数据库连接均应在不使用此连接时返回它。 
    309.      *  
    310.      * @param 需返回到连接池中的连接对象 
    311.      */  
    312.   
    313.     public void returnConnection(Connection conn) {  
    314.   
    315.         // 确保连接池存在,如果连接没有创建(不存在),直接返回  
    316.   
    317.         if (connections == null) {  
    318.             System.out.println(" 连接池不存在,无法返回此连接到连接池中 !");  
    319.             return;  
    320.         }  
    321.   
    322.         PooledConnection pConn = null;  
    323.         Enumeration enumerate = connections.elements();  
    324.         // 遍历连接池中的所有连接,找到这个要返回的连接对象  
    325.         while (enumerate.hasMoreElements()) {  
    326.             pConn = (PooledConnection) enumerate.nextElement();  
    327.             // 先找到连接池中的要返回的连接对象  
    328.             if (conn == pConn.getConnection()) {  
    329.                 // 找到了 , 设置此连接为空闲状态  
    330.                 pConn.setBusy(false);  
    331.                 break;  
    332.             }  
    333.   
    334.         }  
    335.   
    336.     }  
    337.   
    338.     /** 
    339.      *  
    340.      * 刷新连接池中所有的连接对象 
    341.      *  
    342.      *  
    343.      */  
    344.   
    345.     public synchronized void refreshConnections() throws SQLException {  
    346.   
    347.         // 确保连接池己创新存在  
    348.         if (connections == null) {  
    349.             System.out.println(" 连接池不存在,无法刷新 !");  
    350.             return;  
    351.         }  
    352.   
    353.         PooledConnection pConn = null;  
    354.         Enumeration enumerate = connections.elements();  
    355.         while (enumerate.hasMoreElements()) {  
    356.             // 获得一个连接对象  
    357.             pConn = (PooledConnection) enumerate.nextElement();  
    358.             // 如果对象忙则等 5 秒 ,5 秒后直接刷新  
    359.             if (pConn.isBusy()) {  
    360.                 wait(5000); // 等 5 秒  
    361.             }  
    362.   
    363.             // 关闭此连接,用一个新的连接代替它。  
    364.             closeConnection(pConn.getConnection());  
    365.             pConn.setConnection(newConnection());  
    366.             pConn.setBusy(false);  
    367.         }  
    368.   
    369.     }  
    370.   
    371.     /** 
    372.      *  
    373.      * 关闭连接池中所有的连接,并清空连接池。 
    374.      */  
    375.   
    376.     public synchronized void closeConnectionPool() throws SQLException {  
    377.   
    378.         // 确保连接池存在,如果不存在,返回  
    379.         if (connections == null) {  
    380.             System.out.println(" 连接池不存在,无法关闭 !");  
    381.             return;  
    382.         }  
    383.         PooledConnection pConn = null;  
    384.         Enumeration enumerate = connections.elements();  
    385.         while (enumerate.hasMoreElements()) {  
    386.             pConn = (PooledConnection) enumerate.nextElement();  
    387.             // 如果忙,等 5 秒  
    388.             if (pConn.isBusy()) {  
    389.                 wait(5000); // 等 5 秒  
    390.             }  
    391.             // 5 秒后直接关闭它  
    392.             closeConnection(pConn.getConnection());  
    393.             // 从连接池向量中删除它  
    394.             connections.removeElement(pConn);  
    395.         }  
    396.   
    397.         // 置连接池为空  
    398.         connections = null;  
    399.     }  
    400.   
    401.     /** 
    402.      *  
    403.      * 关闭一个数据库连接 
    404.      *  
    405.      * @param 需要关闭的数据库连接 
    406.      */  
    407.   
    408.     private void closeConnection(Connection conn) {  
    409.         try {  
    410.             conn.close();  
    411.         } catch (SQLException e) {  
    412.             System.out.println(" 关闭数据库连接出错: " + e.getMessage());  
    413.         }  
    414.     }  
    415.   
    416.     /** 
    417.      *  
    418.      * 使程序等待给定的毫秒数 
    419.      *  
    420.      * @param 给定的毫秒数 
    421.      */  
    422.   
    423.     private void wait(int mSeconds) {  
    424.         try {  
    425.             Thread.sleep(mSeconds);  
    426.         } catch (InterruptedException e) {  
    427.         }  
    428.     }  
    429.   
    430.     /** 
    431.      *  
    432.      * 内部使用的用于保存连接池中连接对象的类 此类中有两个成员,一个是数据库的连接,另一个是指示此连接是否 正在使用的标志。 
    433.      */  
    434.   
    435.     class PooledConnection {  
    436.   
    437.         Connection connection = null;// 数据库连接  
    438.   
    439.         boolean busy = false; // 此连接是否正在使用的标志,默认没有正在使用  
    440.   
    441.         // 构造函数,根据一个 Connection 构告一个 PooledConnection 对象  
    442.         public PooledConnection(Connection connection) {  
    443.             this.connection = connection;  
    444.         }  
    445.   
    446.         // 返回此对象中的连接  
    447.         public Connection getConnection() {  
    448.             return connection;  
    449.         }  
    450.   
    451.         // 设置此对象的,连接  
    452.         public void setConnection(Connection connection) {  
    453.             this.connection = connection;  
    454.         }  
    455.   
    456.         // 获得对象连接是否忙  
    457.         public boolean isBusy() {  
    458.             return busy;  
    459.         }  
    460.   
    461.         // 设置对象的连接正在忙  
    462.         public void setBusy(boolean busy) {  
    463.             this.busy = busy;  
    464.         }  
    465.   
    466.     }  
    467. }  

    ConnectionParam.java 

    Java代码 
      1. package com.kyo.connection;  
      2.   
      3. import java.io.Serializable;  
      4.   
      5. /** 
      6.  * @author niudongjie.pt 数据库连接池参数 
      7.  */  
      8. public class ConnectionParam implements Serializable {  
      9.   
      10.     /** 
      11.      *  
      12.      */  
      13.     private static final long serialVersionUID = 1L;  
      14.   
      15.     private String driver; // 数据库连接驱动  
      16.     private String url; // 数据库连接URL  
      17.     private String user; // 数据库连接user  
      18.     private String password; // 数据库连接password  
      19.     private int minConnection; // 数据库连接池最小连接数  
      20.     private int maxConnection; // 数据库连接池最大连接数  
      21.     private long timeoutValue; // 连接的最大空闲时间  
      22.     private long waitTime; // 取得连接的最大等待时间  
      23.     private int incrementalConnections=5; //连接池自动增加连接的数量  
      24.       
      25.     public String getDriver() {  
      26.         return driver;  
      27.     }  
      28.   
      29.     public void setDriver(String driver) {  
      30.         this.driver = driver;  
      31.     }  
      32.   
      33.     public String getUrl() {  
      34.         return url;  
      35.     }  
      36.   
      37.     public void setUrl(String url) {  
      38.         this.url = url;  
      39.     }  
      40.   
      41.     public String getUser() {  
      42.         return user;  
      43.     }  
      44.   
      45.     public void setUser(String user) {  
      46.         this.user = user;  
      47.     }  
      48.   
      49.     public String getPassword() {  
      50.         return password;  
      51.     }  
      52.   
      53.     public void setPassword(String password) {  
      54.         this.password = password;  
      55.     }  
      56.   
      57.     public int getMinConnection() {  
      58.         return minConnection;  
      59.     }  
      60.   
      61.     public void setMinConnection(int minConnection) {  
      62.         this.minConnection = minConnection;  
      63.     }  
      64.   
      65.     public int getMaxConnection() {  
      66.         return maxConnection;  
      67.     }  
      68.   
      69.     public void setMaxConnection(int maxConnection) {  
      70.         this.maxConnection = maxConnection;  
      71.     }  
      72.   
      73.     public long getTimeoutValue() {  
      74.         return timeoutValue;  
      75.     }  
      76.   
      77.     public void setTimeoutValue(long timeoutValue) {  
      78.         this.timeoutValue = timeoutValue;  
      79.     }  
      80.   
      81.     public long getWaitTime() {  
      82.         return waitTime;  
      83.     }  
      84.   
      85.     public void setWaitTime(long waitTime) {  
      86.         this.waitTime = waitTime;  
      87.     }  
      88.   
      89.     public void setIncrementalConnections(int incrementalConnections) {  
      90.         this.incrementalConnections = incrementalConnections;  
      91.     }  
      92.   
      93.     public int getIncrementalConnections() {  
      94.         return incrementalConnections;  
      95.     }  
      96.   
      97. }  
  • 相关阅读:
    应急响应中find命令总结
    应急响应排查思路
    硬链接与软链接的区别
    Linux开机启动项总结
    android 開發常用網站
    epoll
    Qualcomm platform, the commonly used parameters of charger and battery in device tree file
    why not ovp protection ?
    Performance tuning
    Using adb over wifi
  • 原文地址:https://www.cnblogs.com/jianwei-dai/p/5798358.html
Copyright © 2011-2022 走看看