数据连接池的研究与实现

来源:互联网 发布:网络捕鱼7298.com 编辑:程序博客网 时间:2024/05/19 22:02
数据连接池的研究与实现(跨数据库设计)
转载请说明出处以及作者:Vincent Zhang
http://www.cnblogs.com/0201010031


中心思想:

1,建立一个数据连接池类
2,然后使用一个专门的类去管理数据库连接池拥有的连接的提出和放回。
3,建立n个(n>=1)为特定的数据库服务的类(例如专门用于sqlserver表操作),注意:一个数据库就一个类
4,用第三步创建出来的特定类去连接第二步创建出来的管理数据库连接池的类


现在说如何真正去实现:

1,首先说“建立一个数据连接池类”

这个数据库连接池,是特定的一个数据库连接池。
首先要说的是,这个数据库连接池一定是与实际的数据库连接有关系,在这篇文章里,我们完全能够把它当作存放特定货物的仓库。首先,这里的货物是某一特定数据库的所有连接(Connection).然后是仓库,放在现实代码里面核心的核心其实就是一个Vector<java.sql.Connection>。利用Vector这个类的特性,把所有的Connection放在Vector里面,需要的时候就提取(使用Vector.get方法)出来,不要的时候就放回去(使用Vector.put方法)。所以,整个数据库连接池类。实际就是一个Vector变量的操作--至少,在这篇文章里面是.

总结我上面的那段话,现在我提出我的原理和对这个类的要求:

首先,建立一个核心的Vector在这个类里面:

 

1 private Vector<Connection> freeConnections = new Vector<Connection>();


然后是建立其它的变量,Vector变量没有可用的连接的时候就要新建立一个连接,但是这个新建立的连接不放到Vector里面去,而是直接使用,直到用完以后再把该连接放到Vector里面去,于是,多了一堆变量和函数了:


 

 1         private int userCount;
 2         private int maxConn;
 3         private String name;
 4         private String password;
 5         private String URL;
 6         private String user;
 7 
 8         public DBConnectionPool(String name, String URL, String user,
 9                 String password, int maxConn) {
10             this.name = name;
11             this.URL = URL;
12             this.user = user;
13             this.password = password;
14             this.maxConn = maxConn;
15         
16         
17         
18         
19         public synchronized Connection getConnection() {
20             Connection con = null;
21             if (freeConnections.size() > 0) {
22                 // 获取向量中第一个可用连接
23                 con = (Connection) freeConnections.firstElement();
24                 freeConnections.removeElementAt(0);
25                 try {
26                     if (con.isClosed()) {
27                         log("从连接池" + name + "删除一个无效连接");
28                         // 递归调用自己,尝试再次获取可用连接
29                         con = getConnection();
30                     }
31                 } catch (SQLException e) {
32                     log("从连接池" + name + "删除一个无效连接");
33                     // 递归调用自己,尝试再次获取可用连接
34                     con = getConnection();
35                 }
36             } else if (maxConn == 0 || userCount < maxConn) {
37                 con = newConnection();
38             }
39             if (con != null) {
40                 userCount++;
41             }
42             return con;
43         }
44         
45         
46         private Connection newConnection() {
47             Connection con = null;
48             try {
49                 if (user == null) {
50                     con = DriverManager.getConnection(URL);
51                 } else {
52                     con = DriverManager.getConnection(URL, user, password);
53                 }
54                 log("连接池" + name + "创建一个新的连接");
55             } catch (SQLException e) {
56                 log("无法创建下列URL的连接: " + URL);
57                 return null;
58             }
59             return con;
60         }
61         
62         
63         public synchronized void freeConnection(Connection con) {
64             // 将指定连接加入到向量末尾
65             freeConnections.addElement(con);
66             userCount--;
67             notifyAll();
68         }


 

很明显,在freeConnection的时候,并没有真正释放这个connection,而是把他放回去了Vector了
也就是要注意的是:在实际的编程中,不要close任何一个connection,把唯一的一次connection.close()放到这个数据库连接池和做(更进一步说明的就是:也没有任何的必要去调用这个函数,真的!因为这个数据库连接池的机制已经比较完善了!)

  关闭的代码如下


 

 1         public synchronized void release() {
 2             Enumeration<Connection> allConnections = freeConnections.elements();
 3             while (allConnections.hasMoreElements()) {
 4                 Connection con = (Connection) allConnections.nextElement();
 5                 try {
 6                     con.close();
 7                     log("关闭连接池" + name + "中的一个连接");
 8                 } catch (SQLException e) {
 9                     log("无法关闭连接池" + name + "中的连接");
10                 }
11             }
12             freeConnections.removeAllElements();
13         }


 

这里就是所有的数据库连接池代码了
  

  
  
2,然后我说第二步,“然后使用一个专门的类去管理数据库连接池拥有的连接的提出和放回”
由于整个管理这些数据库连接池的类是1对多的关系(这样才能够实现跨数据库应用),所以这个类拥有如下的特点:
<A>他负责加载系统的xml或者properties文件变量。
<B>他负责创建Driver并且注册(一个数据库一个Driver,然后各个Driver进行注册)
<C>他负责为每个从数据连接池中获取和放入connection.

所以:

对于<A>,有下面的函数去实现:


 

 1     private void loadDrivers(Properties props) {
 2         String driverClasses = props.getProperty("driver");
 3         StringTokenizer st = new StringTokenizer(driverClasses);
 4         while (st.hasMoreElements()) {
 5             String driverClassName = st.nextToken().trim();
 6 
 7             try {
 8                 Driver driver = (Driver) Class.forName(driverClassName).newInstance();
 9                 DriverManager.registerDriver(driver);
10                 drivers.addElement(driver);
11                 log("成功注册JDBC驱动程序" + driverClassName);
12             } catch (Exception e) {
13                 log("无法注册JDBC驱动程序: " + driverClassName + ", 错误: " + e);
14             }
15         }
16     }

对于<B>,有下面的函数去实现:

 1     private void createPools(Properties props) {
 2         Enumeration<?> propNames = props.propertyNames();
 3         while (propNames.hasMoreElements()) {
 4             String name = (String) propNames.nextElement();
 5             if (name.endsWith(".url")) 
 6             {
 7                 String poolName = name.substring(0, name.indexOf("."));
 8                 String url = props.getProperty(poolName + ".url");
 9                 if (url == null
10                 {
11                     log("没有为连接池" + poolName + "指定URL");
12                     continue;
13                 }
14                 String user = props.getProperty(poolName + ".user");
15                 String password = props.getProperty(poolName + ".password");
16                 
17                 String maxconn = props.getProperty(poolName + ".maxconn""0");
18                 int max;
19                 try {
20                     max = Integer.valueOf(maxconn).intValue();
21                 } catch (NumberFormatException e) {
22                     log("错误的最大连接数限制: " + maxconn + " .连接池: " + poolName);
23                     max = 0;
24                 }
25                 DBConnectionPool pool = new DBConnectionPool(poolName, url,
26                         user, password, max);
27                 pools.put(poolName, pool);
28                 log("成功创建连接池" + poolName);
29             }
30         }
31     }


对于C:

 1     /**
 2      * 建构函数私有以防止其它对象创建本类实例
 3      */
 4     private DBConnectionManager() {
 5         init();
 6     }
 7 
 8     /**
 9      * 将连接对象返回给由名字指定的连接池
10      * 
11      * @param name
12      *            在属性文件中定义的连接池名字
13      * @param con
14      *            连接对象
15      */
16     public void freeConnection(String name, Connection con) {
17         DBConnectionPool pool = (DBConnectionPool) pools.get(name);
18         if (pool != null) {
19             pool.freeConnection(con);
20         }
21     }
22 
23     /**
24      * 获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数 限制,则创建并返回新连接
25      * 
26      * @param name
27      *            在属性文件中定义的连接池名字
28      * @return Connection 可用连接或null
29      */
30     public Connection getConnection(String name) {
31         DBConnectionPool pool = (DBConnectionPool) pools.get(name);
32         if (pool != null) {
33             return pool.getConnection();
34         }
35         return null;
36     }
37 
38     /**
39      * 获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制, 则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
40      * 
41      * @param name
42      *            连接池名字
43      * @param time
44      *            以毫秒计的等待时间
45      * @return Connection 可用连接或null
46      */
47     public Connection getConnection(String name, long time) {
48         DBConnectionPool pool = (DBConnectionPool) pools.get(name);
49         if (pool != null) {
50             return pool.getConnection(time);
51         }
52         return null;
53     }
54 
55     /**
56      * 关闭所有连接,撤销驱动程序的注册
57      */
58     public synchronized void release() {
59         // 等待直到最后一个客户程序调用
60         if (--clients != 0) {
61             return;
62         }
63 
64         Enumeration<DBConnectionPool> allPools = pools.elements();
65         while (allPools.hasMoreElements()) {
66             DBConnectionPool pool = (DBConnectionPool) allPools.nextElement();
67             pool.release();
68         }
69         Enumeration<Driver> allDrivers = drivers.elements();
70         while (allDrivers.hasMoreElements()) {
71             Driver driver = (Driver) allDrivers.nextElement();
72             try {
73                 DriverManager.deregisterDriver(driver);
74                 log("撤销JDBC驱动程序 " + driver.getClass().getName() + "的注册");
75             } catch (SQLException e) {
76                 log("无法撤销下列JDBC驱动程序的注册: " + driver.getClass().getName());
77             }
78         }
79     }

 



相信大家也都已经看到有两行代码是这样的:

1 DBConnectionPool pool = new DBConnectionPool(poolName, url,user, password, max);
2 pools.put(poolName, pool);



 

其中,pools变量为Hashtable。也就是说由于这个管理连接池的类直接管理数据库连接池,并且不能够给别的类使用,我现在把这个数据库连接池类作为它的内联类(不知道是不是这样称呼,因为之前都是看书的,第一次用)

 

第三点要说的是“3,建立n个(n>=1)为特定的数据库服务的类(例如专门用于sqlserver表操作),注意:一个数据库就一个类”
在这里,我们实现一个DBConnection类去直接连接--DBConnectionManager类中管理着的管理sqlServer数据库的数据连接池--


主要的就是获取和释放的函数了:

下面的是获取:

 

第三点要说的是“3,建立n个(n>=1)为特定的数据库服务的类(例如专门用于sqlserver表操作),注意:一个数据库就一个类”
在这里,我们实现一个DBConnection类去直接连接--DBConnectionManager类中管理着的管理sqlServer数据库的数据连接池--


主要的就是获取和释放的函数了:

下面的是获取:

 


 

 1     private String DBConnectType = "sqlserver";
 2 
 3     private DBConnectionManager dcm = null;
 4 
 5     void init() {
 6         dcm = DBConnectionManager.getInstance();
 7         conn = dcm.getConnection(DBConnectType);
 8     }
 9 
10     /**
11      * 构造数据库的连接和访问类
12      */
13     public DBConnect() throws Exception {
14         init();
15         stmt = conn.createStatement();
16     }
17 
18     public DBConnect(int resultSetType, int resultSetConcurrency) throws Exception {
19         init();
20         stmt = conn.createStatement(resultSetType, resultSetConcurrency);
21     }
22     
23     


下面的是释放:

 1     public void close() throws Exception {
 2         if (stmt != null) {
 3             stmt.close();
 4             stmt = null;
 5         }
 6         if (prepstmt != null) {
 7             prepstmt.close();
 8             prepstmt = null;
 9         }
10         if (conn != null) {
11 
12             dcm.freeConnection(DBConnectType, conn);
13 
14         }
15 
16     }

看到了麽?全部都没有用close这个函数的!
最后我说的是第四步,其实也就是说怎么去实践这个代码:

 

 1     public static boolean ChkLogin(String _UserName, String _Password) throws Exception {
 2         
 3         DBConnect dbc = null;
 4         boolean IsExist = false;
 5         try {
 6             dbc = new DBConnect();
 7             dbc.prepareStatement("SELECT Password FROM users WHERE UserName = ? ");
 8             dbc.setString(1, _UserName);
 9             
10             ResultSet rs = dbc.executeQuery();
11             if (!rs.next()) 
12             {
13                 IsExist = false;
14             }
15             else 
16             {
17                 if (_Password.equals(rs.getString("Password")))
18                     IsExist = true;
19             }
20         } 
21         catch (Exception e)
22         {
23             System.err.println(e);
24         }
25         finally 
26         {
27             try 
28             {
29                 dbc.close();
30             } 
31             catch (Exception e) 
32             {
33                 e.printStackTrace();
34             }
35         }
36         return IsExist;
37     }
原创粉丝点击