Python 数据库的连接池

在Python中如果对象定义了__del__方法的话,在对象的引用记数为0时会自动调用__del__方法(很象c++中的析构函数),但如果A对象引用B对象,B对象又引用A对象,就形成循环引用,此时A,B对象引用次数都为1。python就无法正常调用__del__方法,原计划在__del__方法里释放的资源自然也就无法释放。

一个连接池拥有多个连接,而每个连接又拥有这个连接池的实例(一个叫pool的属性)。这样就产生了刚刚说的哪个问题。我想到的办法就是在每次从池中获取连接的时候将连接的pool设置为当前实例,然后在归还这个连接的时候再将其设置为None,并且要在这个连接对象的__del__方法中将pool属性设置为None。具体看代码吧。(目前只实现了SQLite3的)

Python代码   收藏代码
  1. ''''' 
  2. Created on 2009-4-17 
  3.  
  4. @author: phyeas 
  5. '''  
  6. import time  
  7. from queue import Queue  
  8.   
  9. class PoolException(Exception):  
  10.     pass  
  11.   
  12. class Pool(object):  
  13.     '''''一个数据库连接池'''  
  14.     def __init__(self, maxActive=5, maxWait=None, init_size=0, db_type="SQLite3", **config):  
  15.         self.__freeConns = Queue(maxActive)  
  16.         self.maxWait = maxWait  
  17.         self.db_type = db_type  
  18.         self.config = config  
  19.         if init_size > maxActive:  
  20.             init_size = maxActive  
  21.         for i in range(init_size):  
  22.             self.free(self._create_conn())  
  23.       
  24.     def __del__(self):  
  25.         print("__del__ Pool..")  
  26.         self.release()  
  27.       
  28.     def release(self):  
  29.         '''''释放资源,关闭池中的所有连接'''  
  30.         print("release Pool..")  
  31.         while self.__freeConns and not self.__freeConns.empty():  
  32.             con = self.get()  
  33.             con.release()  
  34.         self.__freeConns = None  
  35.   
  36.     def _create_conn(self):  
  37.         '''''创建连接 '''  
  38.         if self.db_type in dbcs:  
  39.             return dbcs[self.db_type](**self.config);  
  40.           
  41.     def get(self, timeout=None):  
  42.         '''''获取一个连接 
  43.         @param timeout:超时时间 
  44.         '''  
  45.         if timeout is None:  
  46.             timeout = self.maxWait  
  47.         conn = None  
  48.         if self.__freeConns.empty():#如果容器是空的,直接创建一个连接  
  49.             conn = self._create_conn()  
  50.         else:  
  51.             conn = self.__freeConns.get(timeout=timeout)  
  52.         conn.pool = self  
  53.         return conn  
  54.       
  55.     def free(self, conn):  
  56.         '''''将一个连接放回池中 
  57.         @param conn: 连接对象 
  58.         '''  
  59.         conn.pool = None  
  60.         if(self.__freeConns.full()):#如果当前连接池已满,直接关闭连接  
  61.             conn.release()  
  62.             return  
  63.         self.__freeConns.put_nowait(conn)  
  64.           
  65. from abc import ABCMeta, abstractmethod  
  66.   
  67. class PoolingConnection(object, metaclass=ABCMeta):  
  68.     def __init__(self, **config):  
  69.         self.conn = None  
  70.         self.config = config  
  71.         self.pool = None  
  72.           
  73.     def __del__(self):  
  74.         self.release()  
  75.           
  76.     def __enter__(self):  
  77.         pass  
  78.       
  79.     def __exit__(self, exc_type, exc_value, traceback):  
  80.         self.close()  
  81.           
  82.     def release(self):  
  83.         print("release PoolingConnection..")  
  84.         if(self.conn is not None):  
  85.             self.conn.close()  
  86.             self.conn = None  
  87.         self.pool = None  
  88.               
  89.     def close(self):  
  90.         if self.pool is None:  
  91.             raise PoolException("连接已关闭")  
  92.         self.pool.free(self)  
  93.           
  94.     def __getattr__(self, val):  
  95.         if self.conn is None and self.pool is not None:  
  96.             self.conn = self._create_conn(**self.config)  
  97.         if self.conn is None:  
  98.             raise PoolException("无法创建数据库连接 或连接已关闭")  
  99.         return getattr(self.conn, val)  
  100.  
  101.     @abstractmethod  
  102.     def _create_conn(self, **config):  
  103.         pass  
  104.   
  105. class SQLit3PoolConnection(PoolingConnection):  
  106.     def _create_conn(self, **config):  
  107.         import sqlite3  
  108.         return sqlite3.connect(**config)  
  109.   
  110. dbcs = {"SQLite3":SQLit3PoolConnection}  
  111.   
  112. pool = Pool(database="F:\\test\\a")  
  113.   
  114. def test():  
  115.     conn = pool.get()  
  116.     with conn:  
  117.         for a in conn.execute("SELECT * FROM A"):  
  118.             print(a)  
  119.   
  120. if __name__ == "__main__":  
  121.     test()  
 java:自定义数据库连接池
2013-03-20 23:16:38
标签: 数据库  连接池  java  pool
原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 http://idata.blog.51cto.com/4581576/1159243

连接池是非常好的想法,应用很普遍。自己写一个数据库连接池,并不像想象中那样困难。一般系统对连接池的功能不会有太多要求,使用自己的连接池未必是个坏主意。下面以Oracle为例,但是对Teradata和Greenplum也是可行的。另外我还实现了连接有效性检查(checkConn)和恢复连接(resetConn)的方法。本例编程采用的是JRE1.4.2环境(别忘了准备访问数据库的jar包)。有任何问题请随时留言,欢迎探讨。

在Oracle内创建测试数据:

    
    
  1. drop table my_table;  
  2. create table my_table(  
  3.        field_id varchar2(3),  
  4.        field_content varchar2(60),  
  5.        record_create_date date default sysdate  
  6. );  
  7.  
  8. insert into my_table(field_id,field_content) values('001','this is first record');  
  9. insert into my_table(field_id,field_content) values('002','this is second record');  
  10. insert into my_table(field_id,field_content) values('003','this is third record');  
  11. commit;  

DBPool.java:

    
    
  1. package dataWebService;  
  2.  
  3. import java.sql.DriverManager;  
  4. import java.util.Date;  
  5. import java.sql.Connection;  
  6. import java.sql.SQLException;  
  7. import java.sql.Statement;  
  8.  
  9. public class DBPool{  
  10.     private String cls;  
  11.     private String url;  
  12.     private String usr;  
  13.     private String pss;   
  14.     private int connCount = 3;//连接数  
  15.     private Connection[] connections;//保存数据库连接  
  16.     private String[] connStatus;// 已连可用Y   已连不可用N   未连接X  
  17.     private Date[] lastQueryTime;//时间戳  
  18.       
  19.     public DBPool(DBPoolConfiguration poolConfiguration){  
  20.         this.connCount=poolConfiguration.getConnCount();  
  21.         this.cls=poolConfiguration.getCls();  
  22.         this.url=poolConfiguration.getUrl();  
  23.         this.usr=poolConfiguration.getUsr();  
  24.         this.pss=poolConfiguration.getPss();  
  25.         this.connections=new Connection[this.connCount];  
  26.         this.connStatus=new String[this.connCount];  
  27.         for(int i=0;i<this.connCount;i++){  
  28.             this.connStatus[i]="X";//初始化全部未连接  
  29.         }  
  30.         this.lastQueryTime = new Date[this.connCount];        
  31.     }  
  32.       
  33.     public DBPool(String cls,String url,String usr,String pss){  
  34.         this.cls=cls;  
  35.         this.url=url;  
  36.         this.usr=usr;  
  37.         this.pss=pss;  
  38.         this.connections=new Connection[this.connCount];  
  39.         this.connStatus=new String[this.connCount];  
  40.         for(int i=0;i<this.connCount;i++){  
  41.             this.connStatus[i]="X";//初始化全部未连接  
  42.         }  
  43.         this.lastQueryTime = new Date[this.connCount];  
  44.     }  
  45.  
  46.     public void initPool(){  
  47.         if(connCount<1){  
  48.             System.out.println("请正确设置连接池窗口个数");  
  49.         }else{  
  50.             try{  
  51.                 Class.forName(this.cls);//register class  
  52.             }catch(ClassNotFoundException e){  
  53.                 System.out.println(e.getMessage());  
  54.             }catch(Exception e){  
  55.                 System.out.println(e.getMessage());//other exceptions  
  56.             }  
  57.  
  58.             for(int i=0;i<this.connCount;i++){  
  59.                 try{  
  60.                     this.connections[i]=DriverManager.getConnection(this.url, this.usr, this.pss);  
  61.                     this.connStatus[i]="Y";  
  62.                 }catch(SQLException e){  
  63.                     System.out.println(e.getMessage());  
  64.                 }catch(Exception e){  
  65.                     System.out.println(e.getMessage());//other exceptions  
  66.                 }  
  67.             }     
  68.             System.out.println("initPool is ready...");  
  69.         }//end if  
  70.     }  
  71.  
  72.     public void freePool(){  
  73.         for(int i=0;i<this.connCount;i++){  
  74.             try{  
  75.                 this.connections[i].commit();  
  76.                 this.connections[i].close();  
  77.                 this.connStatus[i]="X";  
  78.                 this.lastQueryTime[i]=null;  
  79.             }catch(Exception e){  
  80.                 try{  
  81.                     this.connections[i].close();  
  82.                     this.connStatus[i]="X";  
  83.                     this.lastQueryTime[i]=null;                   
  84.                 }catch(Exception e1){  
  85.                     System.out.println(e1.getMessage());//just for catch  
  86.                 }  
  87.             }             
  88.         }  
  89.         System.out.println("freePool is over ...");  
  90.     }  
  91.  
  92.     public DBPoolConnection getPoolConn() throws DBPoolIsFullException{  
  93.         DBPoolConnection poolConnection = new DBPoolConnection();  
  94.         poolConnection.connNbr=getConnNbr();  
  95.         if(poolConnection.connNbr==-1){  
  96.             throw new DBPoolIsFullException("连接池已满");  
  97.         }else{  
  98.             poolConnection.conn=getConn(poolConnection.connNbr);  
  99.         }  
  100.         return poolConnection;  
  101.     }  
  102.  
  103.     public void freePoolConn(DBPoolConnection poolConnection){  
  104.         if(poolConnection==null){  
  105.             System.out.println("poolConnection==null,不需要释放");  
  106.         }else{  
  107.             freeConn(poolConnection.connNbr);  
  108.         }  
  109.     }  
  110.       
  111.     public void printPoolStatus(){  
  112.         for(int i=0;i<this.connStatus.length;i++){  
  113.             System.out.println("");  
  114.             System.out.print(this.connStatus[i].toString());  
  115.             if(this.lastQueryTime[i]==null){  
  116.                 System.out.print("-[null] ");  
  117.             }else{  
  118.                 System.out.print("-["+this.lastQueryTime[i].toString()+"] ");  
  119.             }  
  120.         }  
  121.         System.out.println("");  
  122.     }  
  123.       
  124.     public String getCls(){  
  125.         return this.cls;  
  126.     }  
  127.  
  128.     public String getUrl(){  
  129.         return this.url;  
  130.     }  
  131.  
  132.     public String getUsr(){  
  133.         return this.usr;  
  134.     }  
  135.  
  136.     int getConnNbr(){  
  137.         int iConn=-1;  
  138.         for(int i=0;i<this.connCount;i++){  
  139.             if(this.connStatus[i].equals("Y")){  
  140.                 this.lastQueryTime[i]=new Date();  
  141.                 this.connStatus[i]="N";  
  142.                 iConn=i;  
  143.                 break;  
  144.             }  
  145.         }  
  146.         return iConn;  
  147.     }  
  148.       
  149.     Connection getConn(int i){  
  150.         return this.connections[i];  
  151.     }  
  152.           
  153.     void closeConnForTest(DBPoolConnection poolConnection){  
  154.         try{  
  155.             this.connections[poolConnection.connNbr].close();  
  156.         }catch(SQLException e){  
  157.             System.out.println(e.getMessage());   
  158.         }  
  159.     }  
  160.           
  161.     boolean checkConn(DBPoolConnection poolConnection){  
  162.         Statement stmt=null;  
  163.         String checkMessage="";  
  164.         boolean checkResult=true;  
  165.           
  166.         //检查连接是否有效  
  167.         try{  
  168.             String sql = "select * from dual";  
  169.             stmt = this.connections[poolConnection.connNbr].createStatement();  
  170.             stmt.executeQuery(sql);//execute sql  
  171.             stmt.close();  
  172.             checkMessage = "checkConn:checkMessage:execute sql success";  
  173.             System.out.println(checkMessage);  
  174.         }catch(Exception e){  
  175.             checkMessage = e.getMessage();  
  176.             System.out.println(e.getMessage());//other exceptions  
  177.             if(checkMessage==null){  
  178.                 checkMessage="e.getMessage() is null";  
  179.                 System.out.println(checkMessage);  
  180.             }  
  181.             //采取激进重连的策略,尽量避免业务中断  
  182.             if (checkMessage.indexOf("ORA-00942")>=0){  
  183.                 checkResult=true;//不需要重连  
  184.             }else if(checkMessage.indexOf("does not exist")>=0){  
  185.                 checkResult=true;//不需要重连  
  186.             }else if(checkMessage.indexOf("Syntax error")>=0){  
  187.                 checkResult=true;//不需要重连  
  188.             }else{            
  189.                 checkResult=false;//需要重连  
  190.             }  
  191.         }  
  192.         return checkResult;  
  193.     }  
  194.       
  195.     boolean resetConn(DBPoolConnection poolConnection){  
  196.         boolean result=false;//默认不需要重建连接   
  197.           
  198.         if(poolConnection==null){  
  199.             System.out.println("poolConnection==null,不知道您想重设哪个连接");  
  200.         }else if(poolConnection.connNbr==-1){  
  201.             System.out.println("poolConnection.connNbr==-1,不知道您想重设哪个连接");  
  202.         }else{  
  203.             if(checkConn(poolConnection)==true){  
  204.                 System.out.println("连接有效,不需要重设");  
  205.             }else{  
  206.                 //重设连接  
  207.                 try{  
  208.                     Class.forName(this.cls);//register class  
  209.                 }catch(ClassNotFoundException e){  
  210.                     System.out.println(e.getMessage());  
  211.                 }catch(Exception e){  
  212.                     System.out.println(e.getMessage());//other exceptions  
  213.                 }  
  214.                 try{  
  215.                     this.connections[poolConnection.connNbr]=DriverManager.getConnection(this.url, this.usr, this.pss);  
  216.                     this.connStatus[poolConnection.connNbr]="Y";  
  217.                     System.out.println(poolConnection.connNbr+"连接已重建");  
  218.                     result = true;//告知调用者连接已重建  
  219.                 }catch(SQLException e){  
  220.                     System.out.println(e.getMessage());  
  221.                 }catch(Exception e){  
  222.                     System.out.println(e.getMessage());//other exceptions  
  223.                 }     
  224.             }  
  225.         }  
  226.         return result;  
  227.     }  
  228.           
  229.     void freeConn(int i){  
  230.         try{  
  231.             if(i==-1){  
  232.                 System.out.println("i=-1,不需要释放");  
  233.             }else{  
  234.                 this.connections[i].commit();  
  235.             }  
  236.         }catch(SQLException e){  
  237.             System.out.println(e.getMessage());  
  238.         }catch(Exception e){  
  239.             System.out.println(e.getMessage());//other exceptions  
  240.         }  
  241.         this.connStatus[i]="Y";  
  242.     }  
  243. }  

DBPoolConfiguration.java

    
    
  1. package dataWebService;  
  2.  
  3. public class DBPoolConfiguration {  
  4.     private String cls;  
  5.     private String url;  
  6.     private String usr;  
  7.     private String pss;   
  8.     private int connCount;//连接数   
  9.       
  10.     public String getCls() {  
  11.         return cls;  
  12.     }  
  13.     public void setCls(String cls) {  
  14.         this.cls = cls;  
  15.     }  
  16.     public String getUrl() {  
  17.         return url;  
  18.     }  
  19.     public void setUrl(String url) {  
  20.         this.url = url;  
  21.     }  
  22.     public String getUsr() {  
  23.         return usr;  
  24.     }  
  25.     public void setUsr(String usr) {  
  26.         this.usr = usr;  
  27.     }  
  28.     public String getPss() {  
  29.         return pss;  
  30.     }  
  31.     public void setPss(String pss) {  
  32.         this.pss = pss;  
  33.     }  
  34.     public int getConnCount() {  
  35.         return connCount;  
  36.     }  
  37.     public void setConnCount(int connCount) {  
  38.         this.connCount = connCount;  
  39.     }  

DBPoolConnection.java:

    
    
  1. package dataWebService;  
  2.  
  3. import java.sql.Connection;  
  4.  
  5. public class DBPoolConnection{  
  6.     public int connNbr=-1;  
  7.     public Connection conn=null;  
  8.     DBPoolConnection(){  
  9.         this.connNbr=-1;  
  10.         this.conn = null;  
  11.     }  

DBPoolIsFullException.java

    
    
  1. package dataWebService;  
  2.  
  3. public class DBPoolIsFullException extends Exception{  
  4.     static final long serialVersionUID=1L;  
  5.     DBPoolIsFullException(String message){  
  6.         super(message);  
  7.     }  

Test.java

    
    
  1. package myAction;  
  2.  
  3. import dataWebService.DBPool;  
  4. import dataWebService.DBPoolConnection;  
  5. import dataWebService.DBPoolConfiguration;  
  6. import java.sql.ResultSet;  
  7. import java.sql.ResultSetMetaData;  
  8. import java.sql.Statement;  
  9.  
  10. public class Test {  
  11.     static String rpad(String str,int len){  
  12.         String s = str;  
  13.         if(s==null){  
  14.             s="";  
  15.         }  
  16.         while(s.getBytes().length<len){  
  17.             s += " ";  
  18.         }  
  19.         return s;  
  20.     }  
  21.       
  22.     public static void main(String[] args) {          
  23.         //初始化  
  24.         String cls ="",url="",usr="",pss="",sql="";  
  25.         Statement stmt=null;  
  26.         ResultSet rs=null;  
  27.         String gapStr="|";//分隔符  
  28.         int connCount=2;//最大连接数  
  29.  
  30.         //连接Oracle  配置  
  31.         cls = "oracle.jdbc.driver.OracleDriver";  
  32.         url = "jdbc:oracle:thin:@localhost:1521:myoradb";  
  33.         usr = "abc";  
  34.         pss = "123";  
  35.           
  36.         sql = "select t.field_id,t.field_content,to_char(t.record_create_date,'YYYYMMDD') day from my_table t";  
  37.  
  38.         DBPoolConfiguration poolConfiguration=new DBPoolConfiguration();  
  39.         poolConfiguration.setCls(cls);  
  40.         poolConfiguration.setUrl(url);  
  41.         poolConfiguration.setUsr(usr);  
  42.         poolConfiguration.setPss(pss);  
  43.         poolConfiguration.setConnCount(connCount);  
  44.           
  45.         DBPool myPool = new DBPool(poolConfiguration);  
  46.         myPool.initPool();  
  47.  
  48.           
  49.         System.out.println("");  
  50.         System.out.print("after init Pool");  
  51.         myPool.printPoolStatus();  
  52.         System.out.println("");  
  53.           
  54.         DBPoolConnection c1=null;  
  55.  
  56.         try{  
  57.             c1 = myPool.getPoolConn();  
  58.  
  59.             System.out.println("");  
  60.             System.out.print("after getPoolConn");  
  61.             myPool.printPoolStatus();  
  62.             System.out.println("");           
  63.               
  64.             stmt = c1.conn.createStatement();  
  65.             rs = stmt.executeQuery(sql);  
  66.  
  67.             ResultSetMetaData md = rs.getMetaData();  
  68.               
  69.             String recordHead = "";  
  70.             int colCount = md.getColumnCount();  
  71.             for(int i=1;i<=colCount;i++){  
  72.                 if(recordHead.equals("")){  
  73.                     recordHead += rpad(md.getColumnName(i),md.getColumnDisplaySize(i));  
  74.                 }else{  
  75.                     recordHead+= gapStr + rpad(md.getColumnName(i),md.getColumnDisplaySize(i));  
  76.                 }  
  77.             }  
  78.             System.out.println(recordHead);//打印表头  
  79.               
  80.             while(rs.next()){  
  81.                 String tmp = "";  
  82.                 for(int i=1;i<=colCount;i++){  
  83.                     int colSize = md.getColumnDisplaySize(i)>md.getColumnName(i).length()?md.getColumnDisplaySize(i):md.getColumnName(i).length();  
  84.                     if(tmp.equals("")){  
  85.                         tmp += rpad(rs.getString(i),colSize);  
  86.                     }else{  
  87.                         tmp += gapStr + rpad(rs.getString(i),colSize);  
  88.                     }  
  89.                 }  
  90.                 System.out.println(tmp);//打印数据  
  91.             }  
  92.               
  93.             stmt.close();//释放资源但是不关闭连接                        
  94.             myPool.freePoolConn(c1);  
  95.               
  96.             System.out.println("");  
  97.             System.out.print("after freePoolConn");  
  98.             myPool.printPoolStatus();  
  99.             System.out.println("");           
  100.         }catch(Exception e){  
  101.             System.out.println(e.getMessage());  
  102.         }  
  103.  
  104.         myPool.freePool();  
  105.  
  106.     }//end of main  

下面是Test.java的执行结果:

    
    
  1. initPool is ready...  
  2.  
  3. after init Pool  
  4. Y-[null]   
  5. Y-[null]   
  6.  
  7.  
  8. after getPoolConn  
  9. N-[Wed Mar 20 14:46:31 GMT 2013]   
  10. Y-[null]   
  11.  
  12. FIELD_ID|FIELD_CONTENT                                               |DAY       
  13. 001     |this is first record                                        |20130320  
  14. 002     |this is second record                                       |20130320  
  15. 003     |this is third record                                        |20130320  
  16.  
  17. after freePoolConn  
  18. Y-[Wed Mar 20 14:46:31 GMT 2013]   
  19. Y-[null]   
  20.  
  21. freePool is over ... 

 感谢您的耐心读到此处,我相信接下去的文字会更有价值。

保持连接池简单性的几个设计思想(不一定正确):

1)在系统中连接池不应作为一个独立的模块,最好是作为某模块的底层实现。这样可以将超时管理、请求队列、确保资源释放、数据分页(方言不可避免了)等功能剥离出去。

2)固定连接数比动态连接数容易实现,简单的代码更易于维护。

本例有待完善之处(供参考):

1)查询空闲连接要遍历数组,这样当池中的连接数很大时可能会有问题(具体没测过)

2)可以添加连接池阻塞的功能,有时候后台数据库需要重启,或者想重建连接池以提供更多的并发连接数

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值