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. }  
posted @ 2016-08-23 10:46  前度刘郎  阅读(691)  评论(0编辑  收藏  举报
欢迎来到戴建伟的博客!