Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 388|回复: 0

[JDBC学习]很不错的数据库连接池入门代码(详细注释版)

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

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

            
          

            
          
         
       



      


    源码下载:http://file.javaxxz.com/2014/10/11/051734062.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-26 07:23 , Processed in 0.295618 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表