数据连接池的研究与实现

转载请说明出处以及作者: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      }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值