`
eyes_on_you
  • 浏览: 20529 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

jdbc 连接池

 
阅读更多

转自:http://gaojiewyh.iteye.com/blog/411889

     单例模式,它用以确保一个特定的类只有一个对象被实例化。它包含两种类型,有些书上叫singleton模式和Double—Checked Locking模式。

       单例模式注意问题:

    1、拥有一个特定的方法,这个方法被用于实例化需要的对象。当该方法被调用的时候,它检查这个对象是否被实例化。如果已实例化,这个方法仅仅返回这个对象的一个引用。如果对象未被实例化,这个方法将对象实例化并返回这个新的实例的引用。

      2、类的构造函数定义为protectedprivate

      单例模式的格式

(1)懒汉式

 

Java代码   收藏代码
  1. public class Singleton{   
  2. //声明一个静态类的变量指向null   
  3. private static Singleton instance = null;   
  4. //将构造函数设为private private Singleton();   
  5. //设计静态方法,返回类的实例   
  6. public static Singleton getInstance(){  
  7.  if(instance==null){   
  8. instance = new Singleton();   
  9. return instance;   
  10. }   
  11. }   
  12. }   

 

 

 

 

 (2)饿汉式

      饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变 。
     懒汉式优点是延时加载、 是在需要的时候才创建对象。缺点是应该用同步。如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。

 

Java代码   收藏代码
  1. public class Singleton{   
  2. private static Singleton singleton = new Singleton();   
  3. private Singleton (){ }  
  4.  public Singleton getInstance(){  
  5.  return singletion;   
  6. }   
  7. }  

 

典型应用:

数据库连接池管理类的应用

1、数据库连接池管理类

Java代码   收藏代码
  1. package com.cvicse.util;  
  2.   
  3. import java.io.FileInputStream;  
  4. import java.io.FileNotFoundException;  
  5. import java.io.FileWriter;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.PrintWriter;  
  9. import java.sql.Connection;  
  10. import java.sql.Driver;  
  11. import java.sql.DriverManager;  
  12. import java.sql.SQLException;  
  13. import java.util.Date;  
  14. import java.util.Enumeration;  
  15. import java.util.Hashtable;  
  16. import java.util.Properties;  
  17. import java.util.StringTokenizer;  
  18. import java.util.Vector;  
  19.   
  20. /** 
  21.  * 数据库连接池管理类 
  22.  *  
  23.  * @功能 :管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接池的访问. 
  24.  *     客户程序可以调用getInstance()方法访问本类的唯一实例 
  25.  * @创建人 gao_jie 
  26.  * @创建日期 Jun 18, 2009 
  27.  * @版本 1.0 
  28.  *  
  29.  */  
  30. public class DBConnectionManager {  
  31.   
  32.     private static DBConnectionManager instance; // 唯一实例  
  33.     private static int clients; // 连接的客户端  
  34.     private Vector drivers = new Vector();// 驱动集合  
  35.     private Hashtable pools = new Hashtable();// 连接池  
  36.     private Properties dbProps;// 属性文件  
  37.     private PrintWriter log; // 日志变量  
  38.   
  39.     /** 
  40.      * 单例模式建构私有函数以防止其它对象创建本类实例 
  41.      */  
  42.     private DBConnectionManager() {  
  43.         this.init();  
  44.     }  
  45.   
  46.     /** 
  47.      * 采用单例模式,返回唯一实例.如果是第一次调用此方法,则创建实例 
  48.      *  
  49.      * @return DBConnectionManager 唯一实例 
  50.      */  
  51.     public static synchronized DBConnectionManager getInstance() {  
  52.         if (instance == null) {  
  53.             instance = new DBConnectionManager();  
  54.         }  
  55.         clients++;  
  56.         return instance;  
  57.     }  
  58.   
  59.     /** 
  60.      * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 限制,则创建并返回新连接 
  61.      *  
  62.      * @param name 
  63.      *            在属性文件中定义的连接池名字 
  64.      * @return Connection 可用连接或null 
  65.      */  
  66.     public Connection getConnection(String name) {  
  67.         DBConnectionPool dbPool = (DBConnectionPool) pools.get(name);  
  68.         if (dbPool != null) {  
  69.             return dbPool.getConnection();  
  70.         }  
  71.         return null;  
  72.     }  
  73.   
  74.     /** 
  75.      * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 则创建并返回新连接. 否则,在指定的时间内等待其它线程释放连接. 
  76.      *  
  77.      * @param name 
  78.      *            连接池名字 
  79.      * @param time 
  80.      *            以毫秒计的等待时间 
  81.      * @return Connection 可用连接或null 
  82.      */  
  83.     public Connection getConnection(String name, long time) {  
  84.         DBConnectionPool dbPool = (DBConnectionPool) pools.get(name);  
  85.         if (dbPool != null) {  
  86.             return dbPool.getConnection(time);  
  87.         }  
  88.         return null;  
  89.     }  
  90.   
  91.     /** 
  92.      * 将连接对象返回给由名字指定的连接池 
  93.      *  
  94.      * @param name 
  95.      *            在属性文件中定义的连接池名字 
  96.      * @param con 
  97.      *            连接对象 
  98.      */  
  99.     public void freeConnection(String name, Connection con) {  
  100.         DBConnectionPool dbPool = (DBConnectionPool) pools.get(name);  
  101.         if (dbPool != null) {  
  102.             dbPool.freeConnection(con);  
  103.         }  
  104.     }  
  105.   
  106.     /** 
  107.      * 关闭所有连接,撤销驱动程序的注册 
  108.      */  
  109.     public synchronized void release() {  
  110.         // 等待直到最后一个客户程序调用  
  111.         if (--clients != 0) {  
  112.             return;  
  113.         }  
  114.         Enumeration allPools = pools.elements();  
  115.         while (allPools.hasMoreElements()) {  
  116.             DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();  
  117.             pool.release();  
  118.         }  
  119.         Enumeration allDrivers = drivers.elements();  
  120.         while (allDrivers.hasMoreElements()) {  
  121.             Driver driver = (Driver) allDrivers.nextElement();  
  122.             try {  
  123.                 DriverManager.deregisterDriver(driver);  
  124.                 log("撤销JDBC驱动程序 " + driver.getClass().getName() + "的注册");  
  125.             } catch (SQLException e) {  
  126.                 log(e, "无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());  
  127.             }  
  128.         }  
  129.     }  
  130.   
  131.     /** 
  132.      * 读取属性完成初始化 
  133.      */  
  134.     private void init() {  
  135.   
  136.         // 文件流输入方式  
  137.         InputStream fileinputstream = null;  
  138.         try {  
  139.             fileinputstream = new FileInputStream("./src/db.properties");  
  140.         } catch (FileNotFoundException e) {  
  141.             e.printStackTrace();  
  142.         }  
  143.         try {  
  144.             dbProps = new Properties();  
  145.             dbProps.load(fileinputstream);  
  146.         } catch (Exception e) {  
  147.             e.printStackTrace();  
  148.             System.err.println("不能读取属性文件. "  
  149.                     + "请确保db.properties在CLASSPATH指定的路径中");  
  150.             return;  
  151.         }  
  152.   
  153.         String logFile = dbProps.getProperty("logfile",  
  154.                 "DBConnectionManager.log");  
  155.         try {  
  156.             log = new PrintWriter(new FileWriter(logFile, true), true);  
  157.         } catch (IOException e) {  
  158.             System.err.println("无法打开日志文件: " + logFile);  
  159.             log = new PrintWriter(System.err);  
  160.         }  
  161.         // 加载驱动  
  162.         loadDrivers(dbProps);  
  163.         // 创建连接池  
  164.         createPools(dbProps);  
  165.     }  
  166.   
  167.     /** 
  168.      * 装载和注册所有JDBC驱动程序 
  169.      *  
  170.      * @param props 
  171.      *            属性 
  172.      */  
  173.     private void loadDrivers(Properties props) {  
  174.         String driverClasses = props.getProperty("drivers");  
  175.         StringTokenizer st = new StringTokenizer(driverClasses);  
  176.         while (st.hasMoreElements()) {  
  177.             String driverClassName = st.nextToken().trim();  
  178.             try {  
  179.                 Driver driver = (Driver) Class.forName(driverClassName)  
  180.                         .newInstance();  
  181.                 DriverManager.registerDriver(driver);  
  182.                 drivers.addElement(driver);  
  183.                 log("成功注册JDBC驱动程序" + driverClassName);  
  184.             } catch (Exception e) {  
  185.                 log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e);  
  186.             }  
  187.         }  
  188.     }  
  189.   
  190.     /** 
  191.      * 根据指定属性创建连接池实例. 
  192.      *  
  193.      * @param props 
  194.      *            连接池属性 
  195.      */  
  196.     private void createPools(Properties props) {  
  197.         Enumeration propNames = props.propertyNames();  
  198.         while (propNames.hasMoreElements()) {  
  199.             String name = (String) propNames.nextElement();  
  200.             if (name.endsWith(".url")) {  
  201.                 String poolName = name.substring(0, name.lastIndexOf("."));  
  202.                 System.out.println(" poolName ||" + poolName + "|");  
  203.                 String url = props.getProperty(poolName + ".url");  
  204.                 if (url == null) {  
  205.                     log("没有为连接池" + poolName + "指定URL");  
  206.                     continue;  
  207.                 }  
  208.                 String user = props.getProperty(poolName + ".user");  
  209.                 String password = props.getProperty(poolName + ".password");  
  210.                 String maxconn = props.getProperty(poolName + ".maxconn""0");  
  211.                 int max;  
  212.                 try {  
  213.                     max = Integer.valueOf(maxconn).intValue();  
  214.                 } catch (NumberFormatException e) {  
  215.                     log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);  
  216.                     max = 0;  
  217.                 }  
  218.                 DBConnectionPool pool = new DBConnectionPool(poolName, url,  
  219.                         user, password, max);  
  220.                 pools.put(poolName, pool);  
  221.                 log("成功创建连接池" + poolName);  
  222.             }  
  223.         }  
  224.     }  
  225.   
  226.     /** 
  227.      * 将文本信息写入日志文件 
  228.      */  
  229.     private void log(String msg) {  
  230.         log.println(new Date() + ": " + msg);  
  231.     }  
  232.   
  233.     /** 
  234.      * 将文本信息与异常写入日志文件 
  235.      */  
  236.     private void log(Throwable e, String msg) {  
  237.         log.println(new Date() + ": " + msg);  
  238.         e.printStackTrace(log);  
  239.     }  
  240.   
  241.     /*************************************************************************** 
  242.      ************************数据库连接池内部类************************************ 
  243.      **************************************************************************/  
  244.     /** 
  245.      *  
  246.      * @功能:数据库连接池内类 此内部类定义了一个连接池.它能够根据要求创建新连接,直到预定的最大连接数为止. 
  247.      *              在返回连接给客户程序之前,它能够验证连接的有效性. 
  248.      * @创建人 gao_jie 
  249.      * @创建日期 Jun 19, 2009 
  250.      * @版本 1.0 
  251.      *  
  252.      */  
  253.     class DBConnectionPool {  
  254.   
  255.         private String poolName; // 连接池名字  
  256.         private String dbConnUrl; // 数据库的JDBC URL  
  257.         private String dbUserName; // 数据库账号或null  
  258.         private String dbPassWord; // 数据库账号密码或null  
  259.         private int maxConn; // 此连接池允许建立的最大连接数  
  260.         private int checkedOut; // 当前连接数  
  261.         private Vector<Connection> freeConnections; // 保存所有可用连接  
  262.   
  263.         /** 
  264.          * 创建新的连接池构造函数 
  265.          *  
  266.          * @param poolName 
  267.          *            连接池名字 
  268.          * @param dbConnUrl 
  269.          *            数据库的JDBC URL 
  270.          * @param dbUserName 
  271.          *            数据库帐号或 null 
  272.          * @param dbPassWord 
  273.          *            密码或 null 
  274.          * @param maxConn 
  275.          *            此连接池允许建立的最大连接数 
  276.          */  
  277.         public DBConnectionPool(String poolName, String dbConnUrl,  
  278.                 String dbUserName, String dbPassWord, int maxConn) {  
  279.             this.poolName = poolName;  
  280.             this.dbConnUrl = dbConnUrl;  
  281.             this.dbUserName = dbUserName;  
  282.             this.dbPassWord = dbPassWord;  
  283.             this.maxConn = maxConn;  
  284.             this.freeConnections = new Vector<Connection>();  
  285.         }  
  286.   
  287.         /** 
  288.          * 从连接池获得一个可用连接.如果没有空闲的连接且当前连接数小于最大连接 数限制,则创建新连接. 
  289.          * 如原来登记为可用的连接不再有效,则从向量删除之,然后递归调用自己以尝试新的可用连接. 
  290.          */  
  291.         public synchronized Connection getConnection() {  
  292.             Connection conn = null;// 定义连接标量  
  293.             if (freeConnections != null && freeConnections.size() > 0) {  
  294.                 // 获取向量中第一个可用连接  
  295.                 conn = (Connection) freeConnections.firstElement();  
  296.                 freeConnections.removeElementAt(0);  
  297.                 try {  
  298.                     if (conn.isClosed()) {  
  299.                         log("从连接池" + poolName + "删除一个无效连接");  
  300.                         // 递归调用自己,尝试再次获取可用连接  
  301.                         conn = getConnection();  
  302.                     }  
  303.                 } catch (SQLException e) {  
  304.                     log("从连接池" + poolName + "删除一个无效连接");  
  305.                     // 递归调用自己,尝试再次获取可用连接  
  306.                     conn = getConnection();  
  307.                 }  
  308.             } else if (maxConn == 0 || checkedOut < maxConn) {  
  309.                 conn = newConnection();  
  310.             }  
  311.             if (conn != null) {  
  312.                 checkedOut++;  
  313.             }  
  314.             return conn;  
  315.         }  
  316.   
  317.         /** 
  318.          * 从连接池获取可用连接.可以指定客户程序能够等待的最长时间 参见前一个getConnection()方法. 
  319.          *  
  320.          * @param timeout 
  321.          *            以毫秒计的等待时间限制 
  322.          */  
  323.         public synchronized Connection getConnection(long timeout) {  
  324.             long startTime = System.currentTimeMillis();  
  325.             Connection conn = null;// 定义连接标量  
  326.             while ((conn = getConnection()) == null) {  
  327.                 try {  
  328.                     wait(timeout);  
  329.                 } catch (InterruptedException e) {  
  330.                     e.printStackTrace();  
  331.                 }  
  332.                 if ((System.currentTimeMillis() - startTime) >= timeout) {  
  333.                     // wait()返回的原因是超时  
  334.                     return null;  
  335.                 }  
  336.             }  
  337.             return conn;  
  338.         }  
  339.   
  340.         /** 
  341.          * 创建新的连接 
  342.          *  
  343.          * @return 返回数据库连接 
  344.          */  
  345.         private Connection newConnection() {  
  346.             Connection conn = null;// 定义连接标量  
  347.             try {  
  348.                 if (dbUserName == null) {  
  349.                     conn = DriverManager.getConnection(dbConnUrl);  
  350.                 } else {  
  351.                     conn = DriverManager.getConnection(dbConnUrl, dbUserName,  
  352.                             dbPassWord);  
  353.                 }  
  354.                 log("连接池" + poolName + "创建一个新的连接");  
  355.             } catch (SQLException e) {  
  356.                 log(e, "无法创建下列URL的连接: " + dbConnUrl);  
  357.                 return null;  
  358.             }  
  359.             return conn;  
  360.         }  
  361.   
  362.         /** 
  363.          * 将不再使用的连接返回给连接池 
  364.          *  
  365.          * @param con 
  366.          *            客户程序释放的连接 
  367.          */  
  368.         public synchronized void freeConnection(Connection conn) {  
  369.             // 将指定连接加入到向量末尾  
  370.             freeConnections.addElement(conn);  
  371.             checkedOut--;  
  372.             notifyAll(); // 删除等待队列中的所有线程  
  373.         }  
  374.   
  375.         /** 
  376.          * 关闭所有连接 
  377.          */  
  378.         public synchronized void release() {  
  379.             Enumeration<Connection> allConnections = freeConnections.elements();  
  380.             while (allConnections.hasMoreElements()) {  
  381.                 Connection con = (Connection) allConnections.nextElement();  
  382.                 try {  
  383.                     con.close();  
  384.                     log("关闭连接池" + poolName + "中的一个连接");  
  385.                 } catch (SQLException e) {  
  386.                     log(e, "无法关闭连接池" + poolName + "中的连接");  
  387.                 }  
  388.             }  
  389.             freeConnections.removeAllElements();  
  390.         }  
  391.     }  
  392. }  

 

2、测试类

Java代码   收藏代码
  1. /*   
  2.  *  
  3.  * InforGuard Copyright 2008 CVICSE, Co.ltd .  
  4.  * All rights reserved. 
  5.  *            
  6.  * Package:  com.cvicse.util 
  7.  * FileName: Test.java 
  8.  *  
  9.  */  
  10.   
  11. package com.cvicse.util;  
  12.   
  13. import java.sql.Connection;  
  14.   
  15. /** 
  16.  *  
  17.  * @功能 
  18.  * @创建人 gao_jie 
  19.  * @创建日期 Jun 19, 2009 
  20.  * @版本 1.0 
  21.  *  
  22.  */  
  23. public class Test {  
  24.   
  25.     /** 
  26.      * @param args 
  27.      */  
  28.     public static void main(String[] args) {  
  29.         // 文件流输入方式  
  30.         DBConnectionManager connectionManager = DBConnectionManager  
  31.                 .getInstance();  
  32.         try {  
  33.             Thread.sleep(10);  
  34.         } catch (InterruptedException e) {  
  35.             // TODO Auto-generated catch block  
  36.             e.printStackTrace();  
  37.         }  
  38.         Connection conn1 = connectionManager.getConnection("mysql");  
  39.         Connection conn2 = connectionManager.getConnection("mysql");  
  40.         Connection conn3 = connectionManager.getConnection("mysql");  
  41.         Connection conn4 = connectionManager.getConnection("mysql");  
  42.         Connection conn5 = connectionManager.getConnection("mysql");  
  43.         System.out.println(" conn1 == " + conn1);  
  44.         System.out.println(" conn2 == " + conn2);  
  45.         System.out.println(" conn3 == " + conn3);  
  46.         System.out.println(" conn4 == " + conn4);  
  47.         System.out.println(" conn5 == " + conn5);  
  48.   
  49.         connectionManager.freeConnection("mysql", conn1);  
  50.         connectionManager.freeConnection("mysql", conn2);  
  51.         connectionManager.freeConnection("mysql", conn3);  
  52.         connectionManager.freeConnection("mysql", conn4);  
  53.         connectionManager.freeConnection("mysql", conn5);  
  54.         try {  
  55.             Thread.sleep(10);  
  56.         } catch (InterruptedException e) {  
  57.             // TODO Auto-generated catch block  
  58.             e.printStackTrace();  
  59.         }  
  60.         Connection conn6 = connectionManager.getConnection("mysql");  
  61.         Connection conn7 = connectionManager.getConnection("mysql");  
  62.         Connection conn8 = connectionManager.getConnection("mysql");  
  63.         Connection conn9 = connectionManager.getConnection("mysql");  
  64.         Connection conn10 = connectionManager.getConnection("mysql");  
  65.         System.out.println(" conn6 == " + conn6);  
  66.         System.out.println(" conn7 == " + conn7);  
  67.         System.out.println(" conn8 == " + conn8);  
  68.         System.out.println(" conn9 == " + conn9);  
  69.         System.out.println(" conn10 == " + conn10);  
  70.     }  
  71. }  

 

3、测试结果

 conn1 == com.mysql.jdbc.Connection@1f5d386
 conn2 == com.mysql.jdbc.Connection@121f1d
 conn3 == com.mysql.jdbc.Connection@1b8e059
 conn4 == com.mysql.jdbc.Connection@910040
 conn5 == com.mysql.jdbc.Connection@1a786c3
 conn6 == com.mysql.jdbc.Connection@1f5d386
 conn7 == com.mysql.jdbc.Connection@121f1d
 conn8 == com.mysql.jdbc.Connection@1b8e059
 conn9 == com.mysql.jdbc.Connection@910040
 conn10 == com.mysql.jdbc.Connection@1a786c3

 

 

 启动五个线程,释放后再启动仍然是原先的五个线程。

4、实际应用中的配置

上面所实现的连接池在程序开发时如何应用到系统中呢?下面以Servlet为例说明连接池的使用。

  Servlet的生命周期是:在开始建立servlet时,调用其初始化(init)方法。之后每个用户请求都导致一个调用前面建立的实例的service方法的线程。最后,当服务器决定卸载一个servlet时,它首先调用该servlet的 destroy方法。

  根据servlet的特点,我们可以在初始化函数中生成连接池管理类的唯一实例(其中包括创建一个或多个连接池)。如:

public void init() throws ServletException
{
 connMgr = DBConnectionManager.getInstance(); 
}


  然后就可以在service方法中通过连接池名称使用连接池,执行数据库操作。最后在destroy方法中释放占用的系统资源,如:

public void destroy() { 
 connMgr.release(); super.destroy(); 
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics