(转)经典的java数据库连接池代码

来源:互联网 发布:数据库账号密码 编辑:程序博客网 时间:2024/05/20 07:59

源代码如下:

Java代码
  1. import java.sql.Connection;      
  2. import java.sql.DatabaseMetaData;      
  3. import java.sql.Driver;      
  4. import java.sql.DriverManager;      
  5. import java.sql.ResultSet;      
  6. import java.sql.SQLException;      
  7. import java.sql.Statement;      
  8. import java.util.Enumeration;      
  9. import java.util.Vector;      
  10.      
  11. public class ConnectionPool {      
  12.      
  13.     private String jdbcDriver = ""// 数据库驱动      
  14.      
  15.     private String dbUrl = ""// 数据 URL      
  16.      
  17.     private String dbUsername = ""// 数据库用户名      
  18.      
  19.     private String dbPassword = ""// 数据库用户密码      
  20.      
  21.     private String testTable = ""// 测试连接是否可用的测试表名,默认没有测试表      
  22.      
  23.     private int initialConnections = 10// 连接池的初始大小      
  24.      
  25.     private int incrementalConnections = 5;// 连接池自动增加的大小      
  26.      
  27.     private int maxConnections = 50// 连接池最大的大小      
  28.      
  29.     private Vector connections = null// 存放连接池中数据库连接的向量 , 初始时为 null      
  30.      
  31.     // 它中存放的对象为 PooledConnection 型      
  32.      
  33.     public ConnectionPool() {             
  34.     }      
  35.           
  36.     /**    
  37.      *     
  38.      * 构造函数    
  39.      *     
  40.      * @param jdbcDriver    
  41.      *            String JDBC 驱动类串    
  42.      * @param dbUrl    
  43.      *            String 数据库 URL    
  44.      * @param dbUsername    
  45.      *            String 连接数据库用户名    
  46.      * @param dbPassword    
  47.      *            String 连接数据库用户的密码    
  48.      */     
  49.      
  50.     public ConnectionPool(String jdbcDriver, String dbUrl, String dbUsername,      
  51.             String dbPassword) {      
  52.      
  53.         this.jdbcDriver = jdbcDriver;      
  54.      
  55.         this.dbUrl = dbUrl;      
  56.      
  57.         this.dbUsername = dbUsername;      
  58.      
  59.         this.dbPassword = dbPassword;      
  60.      
  61.     }      
  62.      
  63.     /**    
  64.      * 创建一个数据库连接池,连接池中的可用连接的数量采用类成员 initialConnections 中设置的值    
  65.      */     
  66.      
  67.     public synchronized void createPool() throws Exception {      
  68.      
  69.         // 确保连接池没有创建      
  70.      
  71.         // 如果连接池己经创建了,保存连接的向量 connections 不会为空      
  72.      
  73.         if (connections != null) {      
  74.      
  75.             return// 如果己经创建,则返回      
  76.      
  77.         }      
  78.      
  79.         // 实例化 JDBC Driver 中指定的驱动类实例      
  80.      
  81.         Driver driver = (Driver) (Class.forName(this.jdbcDriver).newInstance());      
  82.      
  83.         DriverManager.registerDriver(driver); // 注册 JDBC 驱动程序      
  84.      
  85.         // 创建保存连接的向量 , 初始时有 0 个元素      
  86.      
  87.         connections = new Vector();      
  88.      
  89.         // 根据 initialConnections 中设置的值,创建连接。      
  90.      
  91.         createConnections(this.initialConnections);      
  92.      
  93.         System.out.println(" 数据库连接池创建成功! ");      
  94.      
  95.     }      
  96.      
  97.     /**    
  98.      *     
  99.      * 创建由 numConnections 指定数目的数据库连接 , 并把这些连接    
  100.      *     
  101.      * 放入 connections 向量中    
  102.      *     
  103.      *     
  104.      *     
  105.      * @param numConnections    
  106.      *            要创建的数据库连接的数目    
  107.      *     
  108.      */     
  109.      
  110.     @SuppressWarnings("unchecked")      
  111.     private void createConnections(int numConnections) throws SQLException {      
  112.      
  113.         // 循环创建指定数目的数据库连接      
  114.      
  115.         for (int x = 0; x < numConnections; x++) {      
  116.      
  117.             // 是否连接池中的数据库连接的数量己经达到最大?最大值由类成员 maxConnections      
  118.      
  119.             // 指出,如果 maxConnections 为 0 或负数,表示连接数量没有限制。      
  120.      
  121.             // 如果连接数己经达到最大,即退出。      
  122.      
  123.             if (this.maxConnections > 0     
  124.                     && this.connections.size() >= this.maxConnections) {      
  125.      
  126.                 break;      
  127.      
  128.             }      
  129.      
  130.             // add a new PooledConnection object to connections vector      
  131.      
  132.             // 增加一个连接到连接池中(向量 connections 中)      
  133.      
  134.             try {      
  135.      
  136.                 connections.addElement(new PooledConnection(newConnection()));      
  137.      
  138.             } catch (SQLException e) {      
  139.      
  140.                 System.out.println(" 创建数据库连接失败! " + e.getMessage());      
  141.      
  142.                 throw new SQLException();      
  143.      
  144.             }      
  145.      
  146.             System.out.println(" 数据库连接己创建 ......");      
  147.      
  148.         }      
  149.      
  150.     }      
  151.      
  152.     /**    
  153.      *     
  154.      * 创建一个新的数据库连接并返回它    
  155.      *     
  156.      *     
  157.      *     
  158.      * @return 返回一个新创建的数据库连接    
  159.      *     
  160.      */     
  161.      
  162.     private Connection newConnection() throws SQLException {      
  163.      
  164.         // 创建一个数据库连接      
  165.      
  166.         Connection conn = DriverManager.getConnection(dbUrl, dbUsername,      
  167.                 dbPassword);      
  168.      
  169.         // 如果这是第一次创建数据库连接,即检查数据库,获得此数据库允许支持的      
  170.      
  171.         // 最大客户连接数目      
  172.      
  173.         // connections.size()==0 表示目前没有连接己被创建      
  174.      
  175.         if (connections.size() == 0) {      
  176.      
  177.             DatabaseMetaData metaData = conn.getMetaData();      
  178.      
  179.             int driverMaxConnections = metaData.getMaxConnections();      
  180.      
  181.             // 数据库返回的 driverMaxConnections 若为 0 ,表示此数据库没有最大      
  182.      
  183.             // 连接限制,或数据库的最大连接限制不知道      
  184.      
  185.             // driverMaxConnections 为返回的一个整数,表示此数据库允许客户连接的数目      
  186.      
  187.             // 如果连接池中设置的最大连接数量大于数据库允许的连接数目 , 则置连接池的最大      
  188.      
  189.             // 连接数目为数据库允许的最大数目      
  190.      
  191.             if (driverMaxConnections > 0     
  192.                     && this.maxConnections > driverMaxConnections) {      
  193.      
  194.                 this.maxConnections = driverMaxConnections;      
  195.      
  196.             }      
  197.      
  198.         }      
  199.      
  200.         return conn; // 返回创建的新的数据库连接      
  201.      
  202.     }      
  203.      
  204.     /**    
  205.      *     
  206.      * 通过调用 getFreeConnection() 函数返回一个可用的数据库连接 ,    
  207.      *     
  208.      * 如果当前没有可用的数据库连接,并且更多的数据库连接不能创建(如连接池大小的限制),此函数等待一会再尝试获取。    
  209.      *     
  210.      * @return 返回一个可用的数据库连接对象    
  211.      *     
  212.      */     
  213.      
  214.     public synchronized Connection getConnection() throws SQLException {      
  215.      
  216.         // 确保连接池己被创建      
  217.      
  218.         if (connections == null) {      
  219.      
  220.             return null// 连接池还没创建,则返回 null      
  221.      
  222.         }      
  223.      
  224.         Connection conn = getFreeConnection(); // 获得一个可用的数据库连接      
  225.      
  226.         // 如果目前没有可以使用的连接,即所有的连接都在使用中      
  227.      
  228.         while (conn == null) {      
  229.      
  230.             // 等一会再试      
  231.      
  232.             wait(250);      
  233.      
  234.             conn = getFreeConnection(); // 重新再试,直到获得可用的连接,如果      
  235.      
  236.             // getFreeConnection() 返回的为 null      
  237.      
  238.             // 则表明创建一批连接后也不可获得可用连接      
  239.      
  240.         }      
  241.      
  242.         return conn;// 返回获得的可用的连接      
  243.      
  244.     }      
  245.      
  246.     /**    
  247.      *     
  248.      * 本函数从连接池向量 connections 中返回一个可用的的数据库连接,如果    
  249.      *     
  250.      * 当前没有可用的数据库连接,本函数则根据 incrementalConnections 设置    
  251.      *     
  252.      * 的值创建几个数据库连接,并放入连接池中。    
  253.      *     
  254.      * 如果创建后,所有的连接仍都在使用中,则返回 null    
  255.      *     
  256.      * @return 返回一个可用的数据库连接    
  257.      *     
  258.      */     
  259.      
  260.     private Connection getFreeConnection() throws SQLException {      
  261.      
  262.         // 从连接池中获得一个可用的数据库连接      
  263.      
  264.         Connection conn = findFreeConnection();      
  265.      
  266.         if (conn == null) {      
  267.      
  268.             // 如果目前连接池中没有可用的连接      
  269.      
  270.             // 创建一些连接      
  271.      
  272.             createConnections(incrementalConnections);      
  273.      
  274.             // 重新从池中查找是否有可用连接      
  275.      
  276.             conn = findFreeConnection();      
  277.      
  278.             if (conn == null) {      
  279.      
  280.                 // 如果创建连接后仍获得不到可用的连接,则返回 null      
  281.      
  282.                 return null;      
  283.      
  284.             }      
  285.      
  286.         }      
  287.      
  288.         return conn;      
  289.      
  290.     }      
  291.      
  292.     /**    
  293.      *     
  294.      * 查找连接池中所有的连接,查找一个可用的数据库连接,    
  295.      *     
  296.      * 如果没有可用的连接,返回 null    
  297.      *     
  298.      *     
  299.      *     
  300.      * @return 返回一个可用的数据库连接    
  301.      *     
  302.      */     
  303.      
  304.     private Connection findFreeConnection() throws SQLException {      
  305.      
  306.         Connection conn = null;      
  307.      
  308.         PooledConnection pConn = null;      
  309.      
  310.         // 获得连接池向量中所有的对象      
  311.      
  312.         Enumeration enumerate = connections.elements();      
  313.      
  314.         // 遍历所有的对象,看是否有可用的连接      
  315.      
  316.         while (enumerate.hasMoreElements()) {      
  317.      
  318.             pConn = (PooledConnection) enumerate.nextElement();      
  319.      
  320.             if (!pConn.isBusy()) {      
  321.      
  322.                 // 如果此对象不忙,则获得它的数据库连接并把它设为忙      
  323.      
  324.                 conn = pConn.getConnection();      
  325.      
  326.                 pConn.setBusy(true);      
  327.      
  328.                 // 测试此连接是否可用      
  329.      
  330.                 if (!testConnection(conn)) {      
  331.      
  332.                     // 如果此连接不可再用了,则创建一个新的连接,      
  333.      
  334.                     // 并替换此不可用的连接对象,如果创建失败,返回 null      
  335.      
  336.                     try {      
  337.      
  338.                         conn = newConnection();      
  339.      
  340.                     } catch (SQLException e) {      
  341.      
  342.                         System.out.println(" 创建数据库连接失败! " + e.getMessage());      
  343.      
  344.                         return null;      
  345.      
  346.                     }      
  347.      
  348.                     pConn.setConnection(conn);      
  349.      
  350.                 }      
  351.      
  352.                 break// 己经找到一个可用的连接,退出      
  353.      
  354.             }      
  355.      
  356.         }      
  357.      
  358.         return conn;// 返回找到到的可用连接      
  359.      
  360.     }      
  361.      
  362.     /**    
  363.      * 测试一个连接是否可用,如果不可用,关掉它并返回 false 否则可用返回 true    
  364.      *     
  365.      * @param conn    
  366.      *            需要测试的数据库连接    
  367.      * @return 返回 true 表示此连接可用, false 表示不可用    
  368.      */     
  369.      
  370.     private boolean testConnection(Connection conn) {      
  371.      
  372.         try {      
  373.      
  374.             // 判断测试表是否存在      
  375.      
  376.             if (testTable.equals("")) {      
  377.      
  378.                 // 如果测试表为空,试着使用此连接的 setAutoCommit() 方法      
  379.      
  380.                 // 来判断连接否可用(此方法只在部分数据库可用,如果不可用 ,      
  381.      
  382.                 // 抛出异常)。注意:使用测试表的方法更可靠      
  383.      
  384.                 conn.setAutoCommit(true);      
  385.      
  386.             } else {// 有测试表的时候使用测试表测试      
  387.      
  388.                 // check if this connection is valid      
  389.      
  390.                 Statement stmt = conn.createStatement();      
  391.      
  392.                 ResultSet rs = stmt.executeQuery("select count(*) from "     
  393.                         + testTable);      
  394.      
  395.                 rs.next();      
  396.      
  397.                 System.out.println(testTable + ":表的记录数为:" + rs.getInt(1));      
  398.      
  399.             }      
  400.      
  401.         } catch (SQLException e) {      
  402.      
  403.             // 上面抛出异常,此连接己不可用,关闭它,并返回 false;      
  404.             e.printStackTrace();      
  405.                   
  406.             closeConnection(conn);      
  407.      
  408.             return false;      
  409.      
  410.         }      
  411.      
  412.         // 连接可用,返回 true      
  413.      
  414.         return true;      
  415.      
  416.     }      
  417.      
  418.     /**    
  419.      * 此函数返回一个数据库连接到连接池中,并把此连接置为空闲。    
  420.      *     
  421.      * 所有使用连接池获得的数据库连接均应在不使用此连接时返回它。    
  422.      *     
  423.      * @param 需返回到连接池中的连接对象    
  424.      */     
  425.      
  426.     public void returnConnection(Connection conn) {      
  427.      
  428.         // 确保连接池存在,如果连接没有创建(不存在),直接返回      
  429.      
  430.         if (connections == null) {      
  431.      
  432.             System.out.println(" 连接池不存在,无法返回此连接到连接池中 !");      
  433.      
  434.             return;      
  435.      
  436.         }      
  437.      
  438.         PooledConnection pConn = null;      
  439.      
  440.         Enumeration enumerate = connections.elements();      
  441.      
  442.         // 遍历连接池中的所有连接,找到这个要返回的连接对象      
  443.      
  444.         while (enumerate.hasMoreElements()) {      
  445.      
  446.             pConn = (PooledConnection) enumerate.nextElement();      
  447.      
  448.             // 先找到连接池中的要返回的连接对象      
  449.      
  450.             if (conn == pConn.getConnection()) {      
  451.      
  452.                 // 找到了 , 设置此连接为空闲状态      
  453.      
  454.                 pConn.setBusy(false);      
  455.      
  456.                 break;      
  457.      
  458.             }      
  459.      
  460.         }      
  461.      
  462.     }      
  463.      
  464.     /**    
  465.      * 刷新连接池中所有的连接对象    
  466.      */     
  467.      
  468.     public synchronized void refreshConnections() throws SQLException {      
  469.      
  470.         // 确保连接池己创新存在      
  471.      
  472.         if (connections == null) {      
  473.      
  474.             System.out.println(" 连接池不存在,无法刷新 !");      
  475.      
  476.             return;      
  477.      
  478.         }      
  479.      
  480.         PooledConnection pConn = null;      
  481.      
  482.         Enumeration enumerate = connections.elements();      
  483.      
  484.         while (enumerate.hasMoreElements()) {      
  485.      
  486.             // 获得一个连接对象      
  487.      
  488.             pConn = (PooledConnection) enumerate.nextElement();      
  489.      
  490.             // 如果对象忙则等 5 秒 ,5 秒后直接刷新      
  491.      
  492.             if (pConn.isBusy()) {      
  493.      
  494.                 wait(5000); // 等 5 秒      
  495.      
  496.             }      
  497.      
  498.             // 关闭此连接,用一个新的连接代替它。      
  499.      
  500.             closeConnection(pConn.getConnection());      
  501.      
  502.             pConn.setConnection(newConnection());      
  503.      
  504.             pConn.setBusy(false);      
  505.      
  506.         }      
  507.      
  508.     }      
  509.      
  510.     /**    
  511.      * 关闭连接池中所有的连接,并清空连接池。    
  512.      */     
  513.      
  514.     public synchronized void closeConnectionPool() throws SQLException {      
  515.      
  516.         // 确保连接池存在,如果不存在,返回      
  517.      
  518.         if (connections == null) {      
  519.      
  520.             System.out.println(" 连接池不存在,无法关闭 !");      
  521.      
  522.             return;      
  523.      
  524.         }      
  525.      
  526.         PooledConnection pConn = null;      
  527.      
  528.         Enumeration enumerate = connections.elements();      
  529.      
  530.         while (enumerate.hasMoreElements()) {      
  531.      
  532.             pConn = (PooledConnection) enumerate.nextElement();      
  533.      
  534.             // 如果忙,等 5 秒      
  535.      
  536.             if (pConn.isBusy()) {      
  537.      
  538.                 wait(5000); // 等 5 秒      
  539.      
  540.             }      
  541.      
  542.             // 5 秒后直接关闭它      
  543.      
  544.             closeConnection(pConn.getConnection());      
  545.      
  546.             // 从连接池向量中删除它      
  547.      
  548.             connections.removeElement(pConn);      
  549.      
  550.         }      
  551.      
  552.         // 置连接池为空      
  553.      
  554.         connections = null;      
  555.      
  556.     }      
  557.      
  558.     /**    
  559.      * 关闭一个数据库连接    
  560.      *     
  561.      * @param 需要关闭的数据库连接    
  562.      */     
  563.      
  564.     private void closeConnection(Connection conn) {      
  565.      
  566.         try {      
  567.      
  568.             conn.close();      
  569.      
  570.         } catch (SQLException e) {      
  571.      
  572.             System.out.println(" 关闭数据库连接出错: " + e.getMessage());      
  573.      
  574.         }      
  575.      
  576.     }      
  577.      
  578.     /**    
  579.      * 使程序等待给定的毫秒数    
  580.      *     
  581.      * @param 给定的毫秒数    
  582.      */     
  583.      
  584.     private void wait(int mSeconds) {      
  585.      
  586.         try {      
  587.      
  588.             Thread.sleep(mSeconds);      
  589.      
  590.         } catch (InterruptedException e) {      
  591.      
  592.         }      
  593.      
  594.     }      
  595.      
  596.     /**    
  597.      * 返回连接池的初始大小    
  598.      *     
  599.      * @return 初始连接池中可获得的连接数量    
  600.      */     
  601.      
  602.     public int getInitialConnections() {      
  603.      
  604.         return this.initialConnections;      
  605.      
  606.     }      
  607.      
  608.     /**    
  609.      * 设置连接池的初始大小    
  610.      *     
  611.      * @param 用于设置初始连接池中连接的数量    
  612.      */     
  613.      
  614.     public void setInitialConnections(int initialConnections) {      
  615.      
  616.         this.initialConnections = initialConnections;      
  617.      
  618.     }      
  619.      
  620.     /**    
  621.      * 返回连接池自动增加的大小 、    
  622.      *     
  623.      * @return 连接池自动增加的大小    
  624.      */     
  625.      
  626.     public int getIncrementalConnections() {      
  627.      
  628.         return this.incrementalConnections;      
  629.      
  630.     }      
  631.      
  632.     /**    
  633.      * 设置连接池自动增加的大小    
  634.      *     
  635.      * @param 连接池自动增加的大小    
  636.      */     
  637.      
  638.     public void setIncrementalConnections(int incrementalConnections) {      
  639.      
  640.         this.incrementalConnections = incrementalConnections;      
  641.      
  642.     }      
  643.      
  644.     /**    
  645.      * 返回连接池中最大的可用连接数量    
  646.      *     
  647.      * @return 连接池中最大的可用连接数量    
  648.      */     
  649.      
  650.     public int getMaxConnections() {      
  651.      
  652.         return this.maxConnections;      
  653.      
  654.     }      
  655.      
  656.     /**    
  657.      * 设置连接池中最大可用的连接数量    
  658.      *     
  659.      * @param 设置连接池中最大可用的连接数量值    
  660.      */     
  661.      
  662.     public void setMaxConnections(int maxConnections) {      
  663.      
  664.         this.maxConnections = maxConnections;      
  665.      
  666.     }      
  667.      
  668.     /**    
  669.      * 获取测试数据库表的名字    
  670.      *     
  671.      * @return 测试数据库表的名字    
  672.      */     
  673.      
  674.     public String getTestTable() {      
  675.      
  676.         return this.testTable;      
  677.      
  678.     }      
  679.      
  680.     /**    
  681.      * 设置测试表的名字    
  682.      *     
  683.      * @param testTable    
  684.      *            String 测试表的名字    
  685.      */     
  686.      
  687.     public void setTestTable(String testTable) {      
  688.      
  689.         this.testTable = testTable;      
  690.      
  691.     }      
  692.      
  693.     /**    
  694.      * 内部使用的用于保存连接池中连接对象的类    
  695.      *     
  696.      * 此类中有两个成员,一个是数据库的连接,另一个是指示此连接是否    
  697.      *     
  698.      * 正在使用的标志。    
  699.      */     
  700.      
  701.     class PooledConnection {      
  702.      
  703.         Connection connection = null;// 数据库连接      
  704.      
  705.         boolean busy = false// 此连接是否正在使用的标志,默认没有正在使用      
  706.      
  707.         // 构造函数,根据一个 Connection 构告一个 PooledConnection 对象      
  708.      
  709.         public PooledConnection(Connection connection) {      
  710.      
  711.             this.connection = connection;      
  712.      
  713.         }      
  714.      
  715.         // 返回此对象中的连接      
  716.      
  717.         public Connection getConnection() {      
  718.      
  719.             return connection;      
  720.      
  721.         }      
  722.      
  723.         // 设置此对象的,连接      
  724.      
  725.         public void setConnection(Connection connection) {      
  726.      
  727.             this.connection = connection;      
  728.      
  729.         }      
  730.      
  731.         // 获得对象连接是否忙      
  732.      
  733.         public boolean isBusy() {      
  734.      
  735.             return busy;      
  736.      
  737.         }      
  738.      
  739.         // 设置对象的连接正在忙      
  740.      
  741.         public void setBusy(boolean busy) {      
  742.      
  743.             this.busy = busy;      
  744.      
  745.         }      
  746.      
  747.     }      
  748.      
  749. }    

 

 

测试类:

代码如下:

Java代码
  1. import java.sql.Connection;      
  2.      
  3. public class ConnectionPoolTest {      
  4.      
  5.     public static void main(String[] args) throws Exception {      
  6.         ConnectionPool connPool = new ConnectionPool("oracle.jdbc.driver.OracleDriver",      
  7.                 "jdbc:oracle:thin:@127.0.0.1:1521:ORCL""scott""tiger");      
  8.      
  9.         connPool.createPool();      
  10.         Connection conn = connPool.getConnection();      
  11.         connPool.closeConnectionPool();      
  12.         connPool.setTestTable("EMP");      
  13.     }      
  14.           
  15. }  
原创粉丝点击