參考博客:http://www.cnblogs.com/xdp-gacl/p/4002804.html
一、 應用程序直接建立數據庫連接模型
應用程序直接每次訪問數據庫時,都建立創建一個數據庫的鏈接,這樣每次建立這樣的連接都需要耗費的資源,當同時有很多用戶在使用應用程序時,可能會導致應用程序崩潰。
圖為應用程序直接建立數據庫連接模型

二、使用數據庫連接池優化模型
數據庫連接池的基本思路是,平時建立適量的數據庫的連接,放在一個集合中,當有用戶需要建立數據庫連接的時候,直接到集合中取出一個數據庫連接對象(Connection),這樣不用再需要重新創建,這樣會節省大量的資源,當用戶不需要在對數據庫進行訪問了,那么就將數據庫連接對象(Connection)重新放回到集合中,以便方便下次使用。
數據庫連接池優化模型圖

1、關於連接池中的連接數量的一些規定:
(1)最小連接數:是連接池一直保持的數據庫連接,所以如果應用程序對數據庫連接的使用量不大,將會有大量的數據庫連接資源被浪費(適量).
(2)最大連接數:是連接池能申請的最大連接數,如果數據庫連接請求超過次數,后面的數據庫連接請求將被加入到等待隊列中,這會影響以后的數據庫操作。通常在使用完起始集合中的連接后,會再重新創建一些數據庫連接對象,用來滿足用戶需求,但是這種新建並不是無限制的。
(3)當使用完的連接對象需要重新放回到集合中以備使用,但是超過最小連接數的連接在使用完不會馬上被釋放,他將被放到連接池中等待重復使用或是超時后最終被釋放。
2、編寫數據庫連接池
簡單思路為:創建一個類繼承DataSource接口,在類中實現靜態的加載出配置文檔db.properties文檔,並創建最小連接量的數據庫連接對象(Connection),添加到Linkedlist(選擇Linkedlist集合原因是便於增刪)集合中。重寫getConnection()函數,在getConnection()函數中實現數據庫連接對象的獲取。
db.properties文檔
1 driver=com.mysql.jdbc.Driver 2 url=jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8 3 username=root 4 password=tiger 5 6 jdbcConnectionInitSize=10
創建數據庫連接池:
1 package JDBC; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.PrintWriter; 6 import java.lang.reflect.InvocationHandler; 7 import java.lang.reflect.Method; 8 import java.lang.reflect.Proxy; 9 import java.sql.Connection; 10 import java.sql.DriverManager; 11 import java.sql.SQLException; 12 import java.sql.SQLFeatureNotSupportedException; 13 import java.util.LinkedList; 14 import java.util.Properties; 15 import java.util.logging.Logger; 16 17 import javax.sql.DataSource; 18 19 public class JdbcConnectionsPool implements DataSource { 20 21 /* 22 * 使用靜態塊代碼,初始化連接池,創建連接池的中最小鏈接數量連接, 23 * 創建linkedlist集合,將這些連接放入集合中 24 */ 25 //創建linkedlist集合 26 private static LinkedList<Connection> linkedlist1=new LinkedList<Connection>(); 27 private static String driver;// 28 private static String url;// 29 private static String username;//數據庫登陸名 30 private static String password;//數據庫的登陸密碼 31 private static int jdbcConnectionInitSize;//最小連接數量 32 private static int max=1; //當前最大連接數量=max*jdbcConnectionInitSize 33 static{ 34 //通過反射機制獲取訪問db.properties文件 35 InputStream is=JdbcConnectionsPool.class.getResourceAsStream("/db.properties"); 36 Properties prop=new Properties(); 37 try { 38 //加載db.properties文件 39 prop.load(is); 40 //獲取db.properties文件中的數據庫連接信息 41 driver=prop.getProperty("driver"); 42 url=prop.getProperty("url"); 43 username=prop.getProperty("username"); 44 password=prop.getProperty("password"); 45 jdbcConnectionInitSize=Integer.parseInt(prop.getProperty("jdbcConnectionInitSize")); 46 47 Class.forName("com.mysql.jdbc.Driver"); 48 49 //創建最小連接數個數據庫連接對象以備使用 50 for(int i=0;i<jdbcConnectionInitSize;i++){ 51 Connection conn=DriverManager.getConnection(url, username, password); 52 System.out.println("獲取到了鏈接" + conn); 53 //將創建好的數據庫連接對象添加到Linkedlist集合中 54 linkedlist1.add(conn); 55 } 56 57 58 } catch (IOException e) { 59 // TODO Auto-generated catch block 60 e.printStackTrace(); 61 } catch (SQLException e) { 62 // TODO Auto-generated catch block 63 e.printStackTrace(); 64 } catch (ClassNotFoundException e) { 65 // TODO Auto-generated catch block 66 e.printStackTrace(); 67 } 68 69 } 70 71 72 @Override 73 public PrintWriter getLogWriter() throws SQLException { 74 // TODO Auto-generated method stub 75 return null; 76 } 77 78 @Override 79 public void setLogWriter(PrintWriter out) throws SQLException { 80 // TODO Auto-generated method stub 81 82 } 83 84 @Override 85 public void setLoginTimeout(int seconds) throws SQLException { 86 // TODO Auto-generated method stub 87 88 } 89 90 @Override 91 public int getLoginTimeout() throws SQLException { 92 // TODO Auto-generated method stub 93 return 0; 94 } 95 96 @Override 97 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 98 // TODO Auto-generated method stub 99 return null; 100 } 101 102 @Override 103 public <T> T unwrap(Class<T> iface) throws SQLException { 104 // TODO Auto-generated method stub 105 return null; 106 } 107 108 @Override 109 public boolean isWrapperFor(Class<?> iface) throws SQLException { 110 // TODO Auto-generated method stub 111 return false; 112 } 113 114 /* 115 * 實現數據庫連接的獲取和新創建 116 */ 117 @Override 118 public Connection getConnection() throws SQLException { 119 //如果集合中沒有數據庫連接對象了,且創建的數據庫連接對象沒有達到最大連接數量,可以再創建一組數據庫連接對象以備使用 120 if(linkedlist1.size()==0&&max<=5){ 121 try { 122 Class.forName("com.mysql.jdbc.Driver"); 123 } catch (ClassNotFoundException e) { 124 // TODO Auto-generated catch block 125 e.printStackTrace(); 126 } 127 for(int i=0;i<jdbcConnectionInitSize;i++){ 128 Connection conn=DriverManager.getConnection(url, username, password); 129 System.out.println("獲取到了鏈接" + conn); 130 //將創建好的數據庫連接對象添加到Linkedlist集合中 131 linkedlist1.add(conn); 132 } 133 max++; 134 } 135 if(linkedlist1.size()>0){ 136 //從linkedlist集合中取出一個數據庫鏈接對象Connection使用 137 Connection conn1=linkedlist1.removeFirst(); 138 System.out.println("linkedlist1數據庫連接池大小是" + linkedlist1.size()); 139 /*返回一個Connection對象,並且設置Connection對象方法調用的限制, 140 *當調用connection類對象的close()方法時會將Connection對象重新收集放入linkedlist集合中。 141 */ 142 return (Connection) Proxy.newProxyInstance(conn1.getClass().getClassLoader(),//這里換成JdbcConnectionsPool.class.getClassLoader();也行 143 conn1.getClass().getInterfaces(), new InvocationHandler() { 144 145 @Override 146 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 147 if(!method.getName().equalsIgnoreCase("close")){ 148 return method.invoke(conn1, args); 149 }else{ 150 linkedlist1.add(conn1); 151 System.out.println(conn1+"對象被釋放,重新放回linkedlist集合中!"); 152 System.out.println("此時Linkedlist集合中有"+linkedlist1.size()+"個數據庫連接對象!"); 153 return null; 154 } 155 } 156 }); 157 }else{ 158 System.out.println("連接數據庫失敗!"); 159 } 160 return null; 161 } 162 163 @Override 164 public Connection getConnection(String username, String password) throws SQLException { 165 166 return null; 167 } 168 169 }
進一步封裝一些相關數據庫的類的方法
1 package JDBC; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 8 public class JdbcConnectionPoolTest { 9 10 /** 11 * @Field: pool 12 * 數據庫連接池 13 */ 14 private static JdbcConnectionsPool pool = new JdbcConnectionsPool(); 15 16 /** 17 * @Method: getConnection 18 * @Description: 從數據庫連接池中獲取數據庫連接對象 19 * @return Connection數據庫連接對象 20 * @throws SQLException 21 */ 22 public static Connection getConnection() throws SQLException{ 23 return pool.getConnection(); 24 } 25 26 /** 27 * @Method: release 28 * @Description: 釋放資源, 29 * 釋放的資源包括Connection數據庫連接對象,負責執行SQL命令的Statement對象,存儲查詢結果的ResultSet對象 30 * @param conn 31 * @param st 32 * @param rs 33 */ 34 public static void release(Connection conn,Statement st,ResultSet rs){ 35 if(rs!=null){ 36 try{ 37 //關閉存儲查詢結果的ResultSet對象 38 rs.close(); 39 }catch (Exception e) { 40 e.printStackTrace(); 41 } 42 rs = null; 43 } 44 if(st!=null){ 45 try{ 46 //關閉負責執行SQL命令的Statement對象 47 st.close(); 48 }catch (Exception e) { 49 e.printStackTrace(); 50 } 51 } 52 53 if(conn!=null){ 54 try{ 55 //關閉Connection數據庫連接對象 56 conn.close(); 57 }catch (Exception e) { 58 e.printStackTrace(); 59 } 60 } 61 } 62 63 }
調試代碼:
1 package JDBC; 2 3 import java.sql.Blob; 4 import java.sql.CallableStatement; 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Types; 9 10 public class TestJdbcPool { 11 12 public static void main(String[] args) throws SQLException { 13 //實例化封裝了有關數據庫類方法類的對象 14 JdbcConnectionPoolTest jcpt=new JdbcConnectionPoolTest(); 15 //獲得數據庫連接對象 16 Connection conn=jcpt.getConnection(); 17 //下面代碼是存儲過程的調用 18 String s="call SP_select_nofilter6(?,?,?) "; 19 CallableStatement cst=conn.prepareCall(s); 20 cst.setInt(2, 2); 21 cst.registerOutParameter(1, Types.VARCHAR); 22 cst.registerOutParameter(3, Types.BLOB); 23 ResultSet rs=cst.executeQuery(); 24 String name=cst.getString(1); 25 Blob b=cst.getBlob(3); 26 27 System.out.println("name:"+name+" Blob:"+b); 28 //關閉所有的數據庫資源 29 jcpt.release(conn, cst, rs); 30 } 31 }
運行結果:
1 獲取到了鏈接com.mysql.jdbc.Connection@5f184fc6 2 獲取到了鏈接com.mysql.jdbc.Connection@723279cf 3 獲取到了鏈接com.mysql.jdbc.Connection@4e50df2e 4 獲取到了鏈接com.mysql.jdbc.Connection@7cc355be 5 獲取到了鏈接com.mysql.jdbc.Connection@52cc8049 6 獲取到了鏈接com.mysql.jdbc.Connection@7530d0a 7 獲取到了鏈接com.mysql.jdbc.Connection@4fca772d 8 獲取到了鏈接com.mysql.jdbc.Connection@7cd84586 9 獲取到了鏈接com.mysql.jdbc.Connection@70177ecd 10 獲取到了鏈接com.mysql.jdbc.Connection@cc34f4d 11 linkedlist1數據庫連接池大小是9 12 name:xiao Blob:com.mysql.jdbc.Blob@5197848c 13 com.mysql.jdbc.Connection@5f184fc6對象被釋放,重新放回linkedlist集合中! 14 此時Linkedlist集合中有10個數據庫連接對象!
標紅的代碼是比較重要的代碼段~,其中Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序,loader參數定義代理類的類加載器,interfaces - 代理類要實現的接口列表,h - 指派方法調用的調用處理程序 。
三、兩個開源的數據庫連接池
在使用了數據庫連接池之后,在項目的實際開發中就不需要編寫連接數據庫的代碼了,直接從數據源獲得數據庫的連接。
1、dbcp連接
(1)導入相關jar包
commons-dbcp2-2.1.1.jar
commons-pool2-2.4.2.jar
commoms-logging-1.2.jar
(2)在項目根目錄增加配置文件dbcp.properties
1 #連接設置 2 driverClassName=com.mysql.jdbc.Driver 3 url=jdbc:mysql://localhost:3306/jdbcstudy 4 username=root 5 password=XDP 6 7 #<!-- 初始化連接 --> 8 initialSize=10 9 10 #最大連接數量 11 maxActive=50 12 13 #<!-- 最大空閑連接 --> 14 maxIdle=20 15 16 #<!-- 最小空閑連接 --> 17 minIdle=5 18 19 #<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 --> 20 maxWait=60000 21 22 23 #JDBC驅動建立連接時附帶的連接屬性屬性的格式必須為這樣:[屬性名=property;] 24 #注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這里不需要包含他們。 25 connectionProperties=useUnicode=true;characterEncoding=UTF8 26 27 #指定由連接池所創建的連接的自動提交(auto-commit)狀態。 28 defaultAutoCommit=true 29 30 #driver default 指定由連接池所創建的連接的只讀(read-only)狀態。 31 #如果沒有設置該值,則“setReadOnly”方法將不被調用。(某些驅動並不支持只讀模式,如:Informix) 32 defaultReadOnly= 33 34 #driver default 指定由連接池所創建的連接的事務級別(TransactionIsolation)。 35 #可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE 36 defaultTransactionIsolation=READ_UNCOMMITTED
(3)程序實現dbcp連接
代碼演示:
數據庫對象的代理類(封裝Connection類的一些方法)
1 package DBCP; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Statement; 9 import java.util.Properties; 10 11 import javax.sql.DataSource; 12 13 import org.apache.commons.dbcp.BasicDataSourceFactory; 14 15 public class DBCPUtil { 16 private static DataSource ds; 17 private static final String configFile="/dbcp.properties"; 18 19 public DBCPUtil(){ 20 //實例化properties對象用於加載配置文件 21 Properties prop=new Properties(); 22 InputStream is=DBCPUtil.class.getResourceAsStream(configFile); 23 try { 24 prop.load(is); 25 ds=BasicDataSourceFactory.createDataSource(prop); 26 } catch (IOException e) { 27 // TODO Auto-generated catch block 28 e.printStackTrace(); 29 } catch (Exception e) { 30 // TODO Auto-generated catch block 31 e.printStackTrace(); 32 } 33 } 34 /* 35 * 獲取數據庫連接對象 36 */ 37 public Connection getConn(){ 38 Connection conn=null; 39 if(ds!=null){ 40 try { 41 conn=ds.getConnection(); 42 conn.setAutoCommit(false);//設置禁止操作自動提交的情況 43 } catch (SQLException e) { 44 // TODO Auto-generated catch block 45 e.printStackTrace(); 46 } 47 return conn; 48 } 49 return conn; 50 } 51 /* 52 * 封裝數據庫相關資源的關閉工作 53 */ 54 public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{ 55 if(rs!=null){ 56 rs.close(); 57 } 58 if(st!=null){ 59 st.close(); 60 } 61 if(conn!=null){ 62 conn.close(); 63 } 64 } 65 }
代碼調用:
1 package DBCP; 2 3 import java.sql.Blob; 4 import java.sql.CallableStatement; 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Types; 9 10 public class DbcpTest { 11 12 public static void main(String[] args) throws SQLException { 13 //實例化數據庫連接的代理類 14 DBCPUtil dbcpUtil=new DBCPUtil(); 15 //獲得數據庫連接對象 16 Connection conn=dbcpUtil.getConn(); 17 //下面代碼是存儲過程的調用 18 String s="call SP_select_nofilter6(?,?,?) "; 19 CallableStatement cst=conn.prepareCall(s); 20 cst.setInt(2, 2); 21 cst.registerOutParameter(1, Types.VARCHAR); 22 cst.registerOutParameter(3, Types.BLOB); 23 ResultSet rs=cst.executeQuery(); 24 String name=cst.getString(1); 25 Blob b=cst.getBlob(3); 26 27 System.out.println("name:"+name+" Blob:"+b); 28 //關閉資源 29 dbcpUtil.close(rs, cst, conn); 30 } 31 32 }
運行結果:
name:xiao Blob:com.mysql.jdbc.Blob@30946e09
2、c3p0連接池
c3p0是一個開源的JDBC連接池,它實現了數據源和JNDI綁定支持JDBC3和JDBC2的標准擴展
(1)導入相關的jar包
cc3p0-0.9.2-pre4.jar
mchange-commons-java-0.2.2.jar
如果是oracle數據庫還需要添加c3p0-oracle-thin-extras-0.9.2-pre1.jar
(2)在項目根目錄下增加配置文件
1)c3p0.properties
1 ##配置除user,password,minpoolsize,maxpoolsize的參數 2 ##[注意] 整數值不能有空格 3 #連接設置 4 driverClassName=com.mysql.jdbc.Driver 5 url=jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8 6 username=root 7 password=tiger 8 9 #初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間。Default: 3 10 c3p0.initialPoolSize=10 11 12 #當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 13 c3p0.acquireIncrement=3 14 15 #最大空閑時間,60秒內未使用則連接被丟棄。若為0則永不丟棄。Default: 0 16 #maxIdleTime應該小於MySQL的wait_timeout的值 17 c3p0.maxIdleTime=600 18 19 #定義在從數據庫獲取新連接失敗后重復嘗試的次數。Default: 30 20 c3p0.acquireRetryAttempts=5 21 22 #兩次連接中間隔時間,單位毫秒。Default: 1000 23 c3p0.acquireRetryDelay=1000 24 25 #連接關閉時默認將所有未提交的操作回滾。Default: false 26 c3p0.autoCommitOnClose=false 27 28 #c3p0將建一張名為Test的空表,並使用其自帶的查詢語句進行測試。如果定義了這個參數那么 29 #屬性preferredTestQuery將被忽略。你不能在這張Test表上進行任何操作,它將只供c3p0測試 30 #使用。Default: null 31 #c3p0.automaticTestTable= 32 33 #獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效 34 #保留,並在下次調用getConnection()的時候繼續嘗試獲取連接。如果設為true,那么在嘗試 35 #獲取連接失敗后該數據源將申明已斷開並永久關閉。Default: false 36 #c3p0.breakAfterAcquireFailure=false 37 38 #當連接池用完時客戶端調用getConnection()后等待獲取新連接的時間,超時后將拋出 39 #SQLException,如設為0則無限期等待。單位毫秒。Default: 0 40 c3p0.checkoutTimeout=10000 41 42 #每60秒檢查所有連接池中的空閑連接。Default: 0 43 c3p0.idleConnectionTestPeriod=600 44 45 #JDBC的標准參數,用以控制數據源內加載的PreparedStatements數量。但由於預緩存的statements 46 #屬於單個connection而不是整個連接池。所以設置這個參數需要考慮到多方面的因素。 47 #如果maxStatements與maxStatementsPerConnection均為0,則緩存被關閉。Default: 0 48 c3p0.maxStatements=100 49 50 #maxStatementsPerConnection定義了連接池內單個連接所擁有的最大緩存statements數。Default: 0 51 c3p0.maxStatementsPerConnection=0 52 53 #c3p0是異步操作的,緩慢的JDBC操作通過幫助進程完成。擴展這些操作可以有效的提升性能 54 #通過多線程實現多個操作同時被執行。Default: 3 55 c3p0.numHelperThreads=3
2)c3p0-config.xml文檔
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!-- 3 c3p0-config.xml必須位於類路徑下面 4 private static ComboPooledDataSource ds; 5 static{ 6 try { 7 ds = new ComboPooledDataSource("MySQL"); 8 } catch (Exception e) { 9 throw new ExceptionInInitializerError(e); 10 } 11 } 12 --> 13 14 <c3p0-config> 15 <!-- 16 C3P0的缺省(默認)配置, 17 如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource();”這樣寫就表示使用的是C3P0的缺省(默認)配置信息來創建數據源 18 --> 19 <default-config> 20 <property name="driverClass">com.mysql.jdbc.Driver</property> 21 <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8</property> 22 <property name="user">root</property> 23 <property name="password">tiger</property> 24 25 <property name="acquireIncrement">5</property> 26 <property name="initialPoolSize">10</property> 27 <property name="minPoolSize">5</property> 28 <property name="maxPoolSize">20</property> 29 </default-config> 30 31 <!-- 32 C3P0的命名配置, 33 如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”這樣寫就表示使用的是name是MySQL的配置信息來創建數據源 34 --> 35 <named-config name="MySQL"> 36 <property name="driverClass">com.mysql.jdbc.Driver</property> 37 <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8</property> 38 <property name="user">root</property> 39 <property name="password">tiger</property> 40 41 <property name="acquireIncrement">5</property> 42 <property name="initialPoolSize">10</property> 43 <property name="minPoolSize">5</property> 44 <property name="maxPoolSize">20</property> 45 </named-config> 46 47 </c3p0-config>
(3)編寫類文件,創建連接池
1)c3p0.properties配置文件情況下
數據庫對象的代理類(封裝Connection類的一些方法)
1 package C3P0; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 8 import com.mchange.v2.c3p0.ComboPooledDataSource; 9 10 public class C3P0Util { 11 12 private static ComboPooledDataSource ds=new ComboPooledDataSource(); 13 14 /* 15 * 獲取數據庫連接對象 16 */ 17 public static Connection getConnection() throws SQLException{ 18 return ds.getConnection(); 19 } 20 21 /* 22 * 封裝數據庫相關資源的關閉工作 23 */ 24 public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{ 25 if(rs!=null){ 26 rs.close(); 27 } 28 if(st!=null){ 29 st.close(); 30 } 31 if(conn!=null){ 32 conn.close(); 33 } 34 } 35 }
代碼調用:
1 package C3P0; 2 3 import java.sql.Blob; 4 import java.sql.CallableStatement; 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Types; 9 10 public class C3P0Test { 11 12 public static void main(String[] args) throws SQLException { 13 C3P0Util c3p0Util=new C3P0Util(); 14 Connection conn=c3p0Util.getConnection(); 15 //下面代碼是存儲過程的調用 16 String s="call SP_select_nofilter6(?,?,?) "; 17 CallableStatement cst=conn.prepareCall(s); 18 cst.setInt(2, 2); 19 cst.registerOutParameter(1, Types.VARCHAR); 20 cst.registerOutParameter(3, Types.BLOB); 21 ResultSet rs=cst.executeQuery(); 22 String name=cst.getString(1); 23 Blob b=cst.getBlob(3); 24 25 System.out.println("name:"+name+" Blob:"+b); 26 //關閉資源 27 c3p0Util.close(rs, cst, conn); 28 } 29 }
運行結果:
1 二月 14, 2017 7:36:12 下午 com.mchange.v2.log.MLog 2 信息: MLog clients using java 1.4+ standard logging. 3 二月 14, 2017 7:36:13 下午 com.mchange.v2.c3p0.C3P0Registry 4 信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10] 5 二月 14, 2017 7:36:13 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 6 信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 5, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 2y4pm69mgrekqw18rvmvn|7aec35a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2y4pm69mgrekqw18rvmvn|7aec35a, idleConnectionTestPeriod -> 600, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 600, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] 7 name:xiao Blob:com.mysql.jdbc.Blob@31b7dea0
2) c3p0-config.xml配置文檔情況下
數據庫對象的代理類(封裝Connection類的一些方法)
1 package C3P0; 2 3 import java.sql.Connection; 4 import java.sql.ResultSet; 5 import java.sql.SQLException; 6 import java.sql.Statement; 7 8 import com.mchange.v2.c3p0.ComboPooledDataSource; 9 10 public class C3P0Util1 { 11 12 private static ComboPooledDataSource ds; 13 14 /* 15 * 獲取數據庫連接對象 16 */ 17 public static Connection getConnection() throws SQLException{ 18 //通過代碼創建C3P0數據庫連接池 19 /*ds = new ComboPooledDataSource(); 20 ds.setDriverClass("com.mysql.jdbc.Driver"); 21 ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy"); 22 ds.setUser("root"); 23 ds.setPassword("XDP"); 24 ds.setInitialPoolSize(10); 25 ds.setMinPoolSize(5); 26 ds.setMaxPoolSize(20);*/ 27 28 //通過讀取C3P0的xml配置文件創建數據源,C3P0的xml配置文件c3p0-config.xml必須放在src目錄下 29 //ds = new ComboPooledDataSource();//使用C3P0的默認配置來創建數據源 30 ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置來創建數據源 31 return ds.getConnection(); 32 } 33 34 /* 35 * 封裝數據庫相關資源的關閉工作 36 */ 37 public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{ 38 if(rs!=null){ 39 rs.close(); 40 } 41 if(st!=null){ 42 st.close(); 43 } 44 if(conn!=null){ 45 conn.close(); 46 } 47 } 48 }
代碼調用:
1 package C3P0; 2 3 import java.sql.Blob; 4 import java.sql.CallableStatement; 5 import java.sql.Connection; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 import java.sql.Types; 9 10 public class C3P0Test1 { 11 12 public static void main(String[] args) throws SQLException { 13 C3P0Util1 c3p0Util1=new C3P0Util1(); 14 Connection conn=c3p0Util1.getConnection(); 15 //下面代碼是存儲過程的調用 16 String s="call SP_select_nofilter6(?,?,?) "; 17 CallableStatement cst=conn.prepareCall(s); 18 cst.setInt(2, 2); 19 cst.registerOutParameter(1, Types.VARCHAR); 20 cst.registerOutParameter(3, Types.BLOB); 21 ResultSet rs=cst.executeQuery(); 22 String name=cst.getString(1); 23 Blob b=cst.getBlob(3); 24 25 System.out.println("name:"+name+" Blob:"+b); 26 //關閉資源 27 c3p0Util1.close(rs, cst, conn); 28 } 29 }
運行結果:
1 二月 14, 2017 8:06:03 下午 com.mchange.v2.log.MLog 2 信息: MLog clients using java 1.4+ standard logging. 3 二月 14, 2017 8:06:03 下午 com.mchange.v2.c3p0.C3P0Registry 4 信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10] 5 二月 14, 2017 8:06:03 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource 6 信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 5, acquireRetryAttempts -> 5, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> MySQL, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2y4pm69mgsgybs1qf3g8s|6e5e91e4, idleConnectionTestPeriod -> 600, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 600, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 20, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] 7 name:xiao Blob:com.mysql.jdbc.Blob@c39f790
總結:其實不管配置文件是c3p0.properties還是c3p0-config.xml,其代碼實現部分沒有多大區別,唯一區別可能就是c3p0-config.xml情況下可以調用含參的ComboPooledDataSource(String s)構造函數,兩個都可以調用其默認的無參構造函數。
3、dbcp和c3p0不同之處
| dbcp | c3p0 |
| spring組織推薦使用 | Hibernate組織推薦使用 |
| 強制關閉連接或者數據庫重啟后無法自動重連 | 強制關閉連接或者數據庫重啟可以自動連接 |
| 沒有自動的去回收空閑連接的功能 | 自動回收空閑的功能 |
| DBCP提供最大連接數 | c3p0提供最大空閑時間 |
| dbcp並沒用相應功能 | c3p0可以控制數據源加載的prepareedstatement數量,並且可以設置幫助線程的數量來提升JDBC操作速度 |
