【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】
一、回顾之前使用的动态代理的方式实现的数据库连接池:
代码:
1 package day16.utils; 2 3 import java.io.IOException; 4 import java.lang.reflect.InvocationHandler; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Proxy; 7 import java.sql.Connection; 8 import java.sql.DriverManager; 9 import java.sql.SQLException; 10 import java.util.LinkedList; 11 import java.util.Properties; 12 13 public class JDBCUtils { 14 private static LinkedList<Connection>pool=new LinkedList<Connection>();//定义连接池,使用LinkedList能提高效率 15 static{ 16 Properties properties=new Properties(); 17 try { 18 properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties")); 19 String driver=properties.getProperty("driver"); 20 String username=properties.getProperty("username"); 21 String password=properties.getProperty("password"); 22 String url=properties.getProperty("url"); 23 int connectionMaxNum=Integer.parseInt(properties.getProperty("connectionMaxNum")); 24 Class.forName(driver); 25 for(int i=0;i<connectionMaxNum;i++) 26 { 27 final Connection conn=DriverManager.getConnection(url, username, password); 28 //关键的一步:进行代理设置。 29 Object proxy=Proxy.newProxyInstance( 30 JDBCUtils.class.getClassLoader() 31 , new Class[]{Connection.class}, 32 new InvocationHandler() { 33 @Override 34 public Object invoke(Object proxy, Method method, Object[] args) 35 throws Throwable { 36 //如果调用了close方法,则不要关闭连接,而应当将连接回收。 37 if(method.getName().equals("close")) 38 { 39 synchronized(pool) 40 { 41 pool.addLast((Connection) proxy);//这里进行强制转换 42 System.out.println("调用了close方法!回收 "+proxy+" ,剩余连接数为"+pool.size()); 43 pool.notify();//从等待池中唤醒任意一条线程 44 } 45 return null;//返回值是null表名拦截该方法的执行。这里的return位置非常重要,一不小心就会是的创建反射对象失败 46 } 47 //如果调用了其他的方法,则要放行 48 else 49 { 50 System.out.println("调用了 "+method.getName()+" 方法,放行!"); 51 return method.invoke(conn, args);//注意这里的对象是conn,而不是其它对象 52 } 53 } 54 }); 55 // System.out.println(proxy); 56 pool.addLast((Connection) proxy);//这里添加的一定是被代理的对象 57 } 58 System.out.println(pool); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } catch (ClassNotFoundException e) { 62 e.printStackTrace(); 63 } catch (SQLException e) { 64 e.printStackTrace(); 65 } 66 } 67 //获得连接对象的方法 68 public static Connection getConnection() 69 { 70 synchronized (pool) { 71 if(pool.size()==0) 72 { 73 System.out.println("连接池中没有可用连接,等待中------------"); 74 try { 75 pool.wait();//等待的方式,使用的是pool************************* 76 } catch (InterruptedException e) { 77 e.printStackTrace(); 78 } 79 return getConnection();//递归调用该方法目的是解锁之后重新获得连接 80 } 81 else 82 { 83 Connection conn=pool.removeFirst(); 84 System.out.println("分配一条连接,剩余连接数目为"+pool.size()); 85 return conn; 86 } 87 } 88 } 89 }
测试:
public void testByProxy() throws SQLException { Connection conn1=JDBCUtils.getConnection(); Connection conn2=JDBCUtils.getConnection(); Connection conn3=JDBCUtils.getConnection(); conn1.close(); Connection conn4=JDBCUtils.getConnection(); }
运行结果:
调用了 toString 方法,放行!
调用了 toString 方法,放行!
调用了 toString 方法,放行!
[com.mysql.jdbc.JDBC4Connection@9c7650, com.mysql.jdbc.JDBC4Connection@1b9c3f, com.mysql.jdbc.JDBC4Connection@af28ad]
分配一条连接,剩余连接数目为2
分配一条连接,剩余连接数目为1
分配一条连接,剩余连接数目为0
调用了 toString 方法,放行!
调用了close方法!回收 com.mysql.jdbc.JDBC4Connection@9c7650 ,剩余连接数为1
分配一条连接,剩余连接数目为0
和之前的相比有些改进:连接池使用LinkedList,效率更高。
功能增强的方式有两种:
1.使用动态代理的方式
2.使用包装的方式
实际上实现数据库连接池只需要实现一个接口:DataSource,然后改连接池就实现了标准化~
二、使用动态代理实现数据库连接池。
1.数据库连接池动态代理实现方式
package day16.utils; //实现DataSource接口使用反射机制实现数据库连接池。 import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.LinkedList; import java.util.Properties; import java.util.logging.Logger; import javax.sql.DataSource; public class DBCPPools implements DataSource{ private LinkedList<Connection>pools=new LinkedList<Connection>(); public DBCPPools() { try { Properties config=new Properties(); config.load(DBCPPools.class.getClassLoader().getResourceAsStream("config.properties")); Class.forName(config.getProperty("driver")); String url=config.getProperty("url"); String username=config.getProperty("username"); String password=config.getProperty("password"); for(int i=0;i<3;i++) { final Connection conn=DriverManager.getConnection(url,username,password); Object proxy=Proxy.newProxyInstance( DBCPPools.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("close")) { synchronized(pools) { pools.addLast((Connection) proxy); System.out.println("调用了close方法!回收 "+proxy+" ,剩余连接数为"+pools.size()); pools.notify(); } return null; } else { // System.out.println(proxy(这里不能写上proxy,否则异常报出!!!!为什么????)+"调用了 "+method.getName()+" 方法,放行!"); System.out.println("调用了 "+method.getName()+" 方法,放行!"); return method.invoke(conn, args); } } }); pools.add((Connection) proxy); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } //最重要的是实现这个方法。 @Override public Connection getConnection(){ synchronized(pools) { if(pools.size()==0) { System.out.println("连接池中没有可用连接,等待中------------"); try { pools.wait(); } catch (InterruptedException e) { e.printStackTrace(); } return getConnection(); } else { Connection conn=pools.removeFirst(); System.out.println("分配一条连接,剩余连接数目为"+pools.size()); return conn; } } } @Override public PrintWriter getLogWriter() throws SQLException { return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { } @Override public void setLoginTimeout(int seconds) throws SQLException { } @Override public int getLoginTimeout() throws SQLException { return 0; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; } @Override public Connection getConnection(String username, String password) throws SQLException { return null; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; } }
2.测试代码
public void testImplementsDataSourceInterfaceByProxy() throws SQLException { DBCPPools pool=new DBCPPools(); Connection conn1=pool.getConnection(); System.out.println(conn1); System.out.println(); Connection conn2=pool.getConnection(); System.out.println(conn2); System.out.println(); Connection conn3=pool.getConnection(); System.out.println(conn3); System.out.println(); // conn1.close();//如果这里没有注释掉,则可以拿到第四条连接,连接池大小默认为3 Connection conn4=pool.getConnection();//第四条连接因为拿不到连接而进入等待池中。 System.out.println(conn4); }
运行结果:
分配一条连接,剩余连接数目为2
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@46530
分配一条连接,剩余连接数目为1
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@8f5f75
分配一条连接,剩余连接数目为0
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@c3feb6
连接池中没有可用连接,等待中------------
将关闭连接的代码放开:
分配一条连接,剩余连接数目为2
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@912767
分配一条连接,剩余连接数目为1
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@1b1ebe5
分配一条连接,剩余连接数目为0
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@1f61490
调用了 toString 方法,放行!
调用了close方法!回收 com.mysql.jdbc.JDBC4Connection@912767 ,剩余连接数为1
分配一条连接,剩余连接数目为0
调用了 toString 方法,放行!
com.mysql.jdbc.JDBC4Connection@912767
三、使用包装的方法实现自定义数据库连接池
1.包装对象:Connection类,这里作为数据库连接池的一个内部类(MyConnection)。
2.使用包装的方法实现的数据库连接池:
1 package day16.utils; 2 3 import java.io.PrintWriter; 4 import java.sql.Array; 5 import java.sql.Blob; 6 import java.sql.CallableStatement; 7 import java.sql.Clob; 8 import java.sql.Connection; 9 import java.sql.DatabaseMetaData; 10 import java.sql.DriverManager; 11 import java.sql.NClob; 12 import java.sql.PreparedStatement; 13 import java.sql.SQLClientInfoException; 14 import java.sql.SQLException; 15 import java.sql.SQLFeatureNotSupportedException; 16 import java.sql.SQLWarning; 17 import java.sql.SQLXML; 18 import java.sql.Savepoint; 19 import java.sql.Statement; 20 import java.sql.Struct; 21 import java.util.LinkedList; 22 import java.util.Map; 23 import java.util.Properties; 24 import java.util.concurrent.Executor; 25 import java.util.logging.Logger; 26 27 import javax.sql.DataSource; 28 29 //测试使用包装的方法定义一个数据库连接池 30 public class MyDBCPpool implements DataSource{ 31 private LinkedList<Connection> pool =new LinkedList<Connection>(); 32 public MyDBCPpool() 33 { 34 Properties properties=new Properties(); 35 try { 36 properties.load(JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties")); 37 String driver=properties.getProperty("driver"); 38 String username=properties.getProperty("username"); 39 String password=properties.getProperty("password"); 40 String url=properties.getProperty("url"); 41 int connectionMaxNum=Integer.parseInt(properties.getProperty("connectionMaxNum")); 42 Class.forName(driver); 43 for(int i=0;i<connectionMaxNum;i++) 44 { 45 Connection conn=DriverManager.getConnection(url,username,password); 46 MyConnection connection =new MyConnection(conn); 47 pool.addLast(connection); 48 } 49 } 50 catch(Exception e) 51 { 52 e.printStackTrace(); 53 } 54 } 55 @Override 56 public Connection getConnection() throws SQLException { 57 System.out.println(pool); 58 synchronized(pool) 59 { 60 if(pool.size()==0) 61 { 62 try { 63 pool.wait(); 64 } catch (InterruptedException e) { 65 e.printStackTrace(); 66 } 67 return getConnection(); 68 } 69 else 70 { 71 Connection conn=pool.removeFirst(); 72 System.out.println("分配出一条连接:"+conn+" 剩余"+pool.size()+" 条连接!"); 73 return conn; 74 } 75 } 76 } 77 @Override 78 public Connection getConnection(String username, String password) 79 throws SQLException { 80 return null; 81 } 82 @Override 83 public PrintWriter getLogWriter() throws SQLException { 84 return null; 85 } 86 @Override 87 public void setLogWriter(PrintWriter out) throws SQLException { 88 } 89 @Override 90 public void setLoginTimeout(int seconds) throws SQLException { 91 } 92 @Override 93 public int getLoginTimeout() throws SQLException { 94 return 0; 95 } 96 // @Override 97 public Logger getParentLogger() throws SQLFeatureNotSupportedException { 98 return null; 99 } 100 @Override 101 public <T> T unwrap(Class<T> iface) throws SQLException { 102 return null; 103 } 104 @Override 105 public boolean isWrapperFor(Class<?> iface) throws SQLException { 106 return false; 107 } 108 class MyConnection implements Connection 109 { 110 private Connection conn; 111 public MyConnection(Connection conn){ 112 this.conn=conn; 113 } 114 //重写close方法 115 @Override 116 public void close() throws SQLException { 117 synchronized(pool) 118 {120 pool.addLast(this);
System.out.println(this+"还连接!剩余连接数:"+pool.size()); 121 pool.notify(); 122 } 123 } 124 @Override 125 public <T> T unwrap(Class<T> iface) throws SQLException { 126 return conn.unwrap(iface); 127 } 128 @Override 129 public boolean isWrapperFor(Class<?> iface) throws SQLException { 130 return conn.isWrapperFor(iface); 131 } 132 @Override 133 public Statement createStatement() throws SQLException { 134 return conn.createStatement(); 135 } 136 @Override 137 public PreparedStatement prepareStatement(String sql) 138 throws SQLException { 139 return conn.prepareStatement(sql); 140 } 141 @Override 142 public CallableStatement prepareCall(String sql) throws SQLException { 143 return conn.prepareCall(sql); 144 } 145 @Override 146 public String nativeSQL(String sql) throws SQLException { 147 return conn.nativeSQL(sql); 148 } 149 @Override 150 public void setAutoCommit(boolean autoCommit) throws SQLException { 151 conn.setAutoCommit(autoCommit); 152 } 153 @Override 154 public boolean getAutoCommit() throws SQLException { 155 return conn.getAutoCommit(); 156 } 157 @Override 158 public void commit() throws SQLException { 159 conn.commit(); 160 } 161 @Override 162 public void rollback() throws SQLException { 163 conn.rollback(); 164 } 165 @Override 166 public boolean isClosed() throws SQLException { 167 return conn.isClosed(); 168 } 169 @Override 170 public DatabaseMetaData getMetaData() throws SQLException { 171 return conn.getMetaData(); 172 } 173 @Override 174 public void setReadOnly(boolean readOnly) throws SQLException { 175 conn.setReadOnly(readOnly); 176 } 177 @Override 178 public boolean isReadOnly() throws SQLException { 179 return conn.isReadOnly(); 180 } 181 @Override 182 public void setCatalog(String catalog) throws SQLException { 183 conn.setCatalog(catalog); 184 } 185 @Override 186 public String getCatalog() throws SQLException { 187 return conn.getCatalog(); 188 } 189 @Override 190 public void setTransactionIsolation(int level) throws SQLException { 191 conn.setTransactionIsolation(level); 192 } 193 @Override 194 public int getTransactionIsolation() throws SQLException { 195 return conn.getTransactionIsolation(); 196 } 197 @Override 198 public SQLWarning getWarnings() throws SQLException { 199 return conn.getWarnings(); 200 } 201 @Override 202 public void clearWarnings() throws SQLException { 203 conn.clearWarnings(); 204 } 205 @Override 206 public Statement createStatement(int resultSetType, 207 int resultSetConcurrency) throws SQLException { 208 return conn.createStatement(resultSetType, resultSetConcurrency); 209 } 210 @Override 211 public PreparedStatement prepareStatement(String sql, 212 int resultSetType, int resultSetConcurrency) 213 throws SQLException { 214 return conn.prepareStatement(sql, resultSetType, resultSetConcurrency); 215 } 216 @Override 217 public CallableStatement prepareCall(String sql, int resultSetType, 218 int resultSetConcurrency) throws SQLException { 219 return conn.prepareCall(sql, resultSetType, resultSetConcurrency); 220 } 221 @Override 222 public Map<String, Class<?>> getTypeMap() throws SQLException { 223 return conn.getTypeMap(); 224 } 225 @Override 226 public void setTypeMap(Map<String, Class<?>> map) throws SQLException { 227 conn.setTypeMap(map); 228 } 229 @Override 230 public void setHoldability(int holdability) throws SQLException { 231 conn.setHoldability(holdability); 232 } 233 @Override 234 public int getHoldability() throws SQLException { 235 return conn.getHoldability(); 236 } 237 @Override 238 public Savepoint setSavepoint() throws SQLException { 239 return conn.setSavepoint(); 240 } 241 @Override 242 public Savepoint setSavepoint(String name) throws SQLException { 243 return conn.setSavepoint(name); 244 } 245 @Override 246 public void rollback(Savepoint savepoint) throws SQLException { 247 conn.rollback(savepoint); 248 } 249 @Override 250 public void releaseSavepoint(Savepoint savepoint) throws SQLException { 251 conn.releaseSavepoint(savepoint); 252 } 253 @Override 254 public Statement createStatement(int resultSetType, 255 int resultSetConcurrency, int resultSetHoldability) 256 throws SQLException { 257 return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); 258 } 259 @Override 260 public PreparedStatement prepareStatement(String sql, 261 int resultSetType, int resultSetConcurrency, 262 int resultSetHoldability) throws SQLException { 263 return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 264 } 265 @Override 266 public CallableStatement prepareCall(String sql, int resultSetType, 267 int resultSetConcurrency, int resultSetHoldability) 268 throws SQLException { 269 return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); 270 } 271 @Override 272 public PreparedStatement prepareStatement(String sql, 273 int autoGeneratedKeys) throws SQLException { 274 return conn.prepareStatement(sql, autoGeneratedKeys); 275 } 276 @Override 277 public PreparedStatement prepareStatement(String sql, 278 int[] columnIndexes) throws SQLException { 279 return conn.prepareStatement(sql, columnIndexes); 280 } 281 @Override 282 public PreparedStatement prepareStatement(String sql, 283 String[] columnNames) throws SQLException { 284 return conn.prepareStatement(sql, columnNames); 285 } 286 @Override 287 public Clob createClob() throws SQLException { 288 return conn.createClob(); 289 } 290 @Override 291 public Blob createBlob() throws SQLException { 292 return conn.createBlob(); 293 } 294 @Override 295 public NClob createNClob() throws SQLException { 296 return conn.createNClob(); 297 } 298 @Override 299 public SQLXML createSQLXML() throws SQLException { 300 return conn.createSQLXML(); 301 } 302 @Override 303 public boolean isValid(int timeout) throws SQLException { 304 return conn.isValid(timeout); 305 } 306 @Override 307 public void setClientInfo(String name, String value) 308 throws SQLClientInfoException { 309 conn.setClientInfo(name, value); 310 } 311 @Override 312 public void setClientInfo(Properties properties) 313 throws SQLClientInfoException { 314 conn.setClientInfo(properties); 315 } 316 @Override 317 public String getClientInfo(String name) throws SQLException { 318 return conn.getClientInfo(name); 319 } 320 @Override 321 public Properties getClientInfo() throws SQLException { 322 return conn.getClientInfo(); 323 } 324 @Override 325 public Array createArrayOf(String typeName, Object[] elements) 326 throws SQLException { 327 return conn.createArrayOf(typeName, elements); 328 } 329 @Override 330 public Struct createStruct(String typeName, Object[] attributes) 331 throws SQLException { 332 return conn.createStruct(typeName, attributes); 333 } 334 @Override 335 public void setSchema(String schema) throws SQLException { 336 } 337 @Override 338 public String getSchema() throws SQLException { 339 return conn.getSchema(); 340 } 341 @Override 342 public void abort(Executor executor) throws SQLException { 343 } 344 @Override 345 public void setNetworkTimeout(Executor executor, int milliseconds) 346 throws SQLException { 347 } 348 @Override 349 public int getNetworkTimeout() throws SQLException { 350 return conn.getNetworkTimeout(); 351 } 352 } 353 }
3.和之前的相比有哪些改动?
(1)将数据库连接池的初始化放在了构造方法中。
(2)连接池中放的是重写的Connection对象。
(3)没有使用动态代理,效率更高。
(4)将重写的Connection类放到了连接池类的内部作为内部类使用。
4.测试代码
public void testMyDBCPpool() throws SQLException { MyDBCPpool pool=new MyDBCPpool(); Connection conn1=pool.getConnection(); System.out.println(conn1); Connection conn2=pool.getConnection(); System.out.println(conn2); Connection conn3=pool.getConnection(); System.out.println(conn3); conn1.close(); Connection conn4=pool.getConnection();//第四条连接因为拿不到连接而进入等待池中。 System.out.println(conn4); }
5.运行结果:
[day16.utils.MyDBCPpool$MyConnection@13f7cd2, day16.utils.MyDBCPpool$MyConnection@11c0042, day16.utils.MyDBCPpool$MyConnection@154fe09] 分配出一条连接:day16.utils.MyDBCPpool$MyConnection@13f7cd2 剩余2 条连接! day16.utils.MyDBCPpool$MyConnection@13f7cd2 [day16.utils.MyDBCPpool$MyConnection@11c0042, day16.utils.MyDBCPpool$MyConnection@154fe09] 分配出一条连接:day16.utils.MyDBCPpool$MyConnection@11c0042 剩余1 条连接! day16.utils.MyDBCPpool$MyConnection@11c0042 [day16.utils.MyDBCPpool$MyConnection@154fe09] 分配出一条连接:day16.utils.MyDBCPpool$MyConnection@154fe09 剩余0 条连接! day16.utils.MyDBCPpool$MyConnection@154fe09 day16.utils.MyDBCPpool$MyConnection@13f7cd2还连接!剩余连接数:1 [day16.utils.MyDBCPpool$MyConnection@13f7cd2] 分配出一条连接:day16.utils.MyDBCPpool$MyConnection@13f7cd2 剩余0 条连接! day16.utils.MyDBCPpool$MyConnection@13f7cd2
分析和总结:实际上使用DBCP数据库连接池原理和这基本上差不多,所以该数据库连接池的名字为MyDBCPpool,下面开始进入正题。
四、DBCP数据库连接池。
1.需要的jar包
2.数据源类:
org.apache.commons.dbcp2.BasicDataSource,但是获取连接的时候使用的是
org.apache.commons.dbcp2.PoolingDataSource
Connection类:PoolGuardConnectionWrapper是PoolingDataSource的内部类。
3.是否回收连接到连接池
代码追踪:
PoolGuardConnectionWrapper的close方法:
super.close()调用的并非是Connection类的方法,而是org.apache.commons.dbcp2.DelegatingConnection类的方法。
closeInternal方法
_conn.close()调用的是Connection接口的方法。
可见实际上真的将连接关闭掉了,而非回收到了连接池中。
4.使用dbcp线程池但是不使用自定义工具类
4.1不使用配置文件
1 public void testDBCP() throws SQLException 2 { 3 BasicDataSource bds=new BasicDataSource(); 4 bds.setDriverClassName("com.mysql.jdbc.Driver"); 5 bds.setUrl("jdbc:mysql://localhost:3306/bms"); 6 bds.setUsername("root"); 7 bds.setPassword("5a6f38"); 8 // bds.setInitialSize(3); 9 bds.setMaxTotal(3); 10 Connection conn=bds.getConnection(); 11 // System.out.println(conn.hashCode()); 12 System.out.println(conn); 13 Connection conn1=bds.getConnection(); 14 System.out.println(conn1); 15 // System.out.println(conn1.hashCode()); 16 Connection conn2=bds.getConnection(); 17 System.out.println(conn2); 18 // System.out.println(conn2.hashCode()); 19 conn.close(); 20 Connection conn3=bds.getConnection(); 21 // System.out.println(conn3.hashCode()); 22 System.out.println(conn3); 23 }
运行结果:
25452873, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver 11678023, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver 8058664, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver 15102604, URL=jdbc:mysql://localhost:3306/bms, UserName=root@localhost, MySQL-AB JDBC Driver
4.2使用配置文件(需要使用一个工厂类BasicDataSourceFactory)
username=root password=5a6f38 url=jdbc:mysql://localhost:3306/test driverClassName=com.mysql.jdbc.Driver initialSize=3 maxTotal=3 #maxTotal的值默认是8,initialSize的值默认也是8
1 public void testAutoConfigMethod() 2 { 3 try { 4 Properties properties=new Properties(); 5 properties.load(Test2.class.getClassLoader().getResourceAsStream("config_dbcp.properties")); 6 DataSource ds=BasicDataSourceFactory.createDataSource(properties); 7 Connection conn=ds.getConnection(); 8 System.out.println(conn); 9 Connection conn1=ds.getConnection(); 10 System.out.println(conn1); 11 Connection conn2=ds.getConnection(); 12 System.out.println(conn2); 13 System.out.println("关闭一条连接之后:"); 14 conn.close(); 15 for(int i=0;i<5;i++) 16 { 17 Connection c=ds.getConnection(); 18 System.out.println(c); 19 } 20 } catch (IOException e) { 21 e.printStackTrace(); 22 } catch (Exception e) { 23 e.printStackTrace(); 24 } 25 }
在这里需要使用一个工厂类:BasicDataSourceFactory
该工厂类可以根据配置文件创建一个数据源DataSource对象。
5.定义工具类简化书写过程。
1 package day16.regular.utils; 2 3 import java.io.IOException; 4 import java.sql.Connection; 5 import java.sql.SQLException; 6 import java.util.Properties; 7 8 import javax.sql.DataSource; 9 10 import org.apache.commons.dbcp2.BasicDataSourceFactory; 11 12 13 //使用第三方jar包创建dbcp连接池 14 public class DataSourceUtils_DBCP { 15 private DataSourceUtils_DBCP(){}//使用私有修饰构造方法,可以防止创建对象,这样可以确保只有一个DataSource对象 16 private static DataSource ds; 17 static 18 { 19 Properties properties=new Properties(); 20 try { 21 properties.load(DataSourceUtils_DBCP.class.getClassLoader().getResourceAsStream("config_dbcp.properties")); 22 ds=BasicDataSourceFactory.createDataSource(properties); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 } 28 } 29 public static Connection getConnection() 30 { 31 Connection conn=null; 32 try { 33 conn=ds.getConnection(); 34 } catch (SQLException e) { 35 e.printStackTrace(); 36 } 37 return conn; 38 } 39 public static DataSource getDataSource() 40 { 41 return ds; 42 } 43 }
五、c3p0数据库连接池。
1.依赖包下载
mchange-commons-java-0.2.9.jar
2.必须使用配置文件,名字必须为:c3p0-config.xml,位置必须在class路径下
1 <?xml version="1.0" encoding="UTF-8"?> 2 <c3p0-config> 3 <!-- 默认配置,只可以出现一次 --> 4 <default-config> 5 <!-- 连接超时设置30秒 --> 6 <property name="checkoutTimeout">30000</property> 7 <!-- 30秒检查一次connection的空闲 --> 8 <property name="idleConnectionTestPeriod">30</property> 9 <!--初始化的池大小 --> 10 <property name="initialPoolSize">2</property> 11 <!-- 最多的一个connection空闲时间 --> 12 <property name="maxIdleTime">30</property> 13 <!-- 最多可以有多少个连接connection --> 14 <property name="maxPoolSize">10</property> 15 <!-- 最少的池中有几个连接 --> 16 <property name="minPoolSize">2</property> 17 <!-- 批处理的语句--> 18 <property name="maxStatements">50</property> 19 <!-- 每次增长几个连接 --> 20 <property name="acquireIncrement">3</property> 21 <property name="driverClass">com.mysql.jdbc.Driver</property> 22 <property name="jdbcUrl"> 23 <![CDATA[jdbc:mysql://10.6.112.200:3306/test?useUnicode=true&characterEncoding=UTF-8]]> 24 </property> 25 <property name="user">root</property> 26 <property name="password">5a6f38</property> 27 </default-config> 28 29 <named-config name="namedconfig"> 30 <!-- 连接超时设置30秒 --> 31 <property name="checkoutTimeout">30000</property> 32 <!-- 30秒检查一次connection的空闲 --> 33 <property name="idleConnectionTestPeriod">30</property> 34 <!--初始化的池大小 --> 35 <property name="initialPoolSize">2</property> 36 <!-- 最多的一个connection空闲时间 --> 37 <property name="maxIdleTime">30</property> 38 <!-- 最多可以有多少个连接connection --> 39 <property name="maxPoolSize">2</property> 40 <!-- 最少的池中有几个连接 --> 41 <property name="minPoolSize">2</property> 42 <!-- 批处理的语句--> 43 <property name="maxStatements">50</property> 44 <!-- 每次增长几个连接 --> 45 <property name="acquireIncrement">2</property> 46 <property name="driverClass">com.mysql.jdbc.Driver</property> 47 <property name="jdbcUrl"> 48 <![CDATA[jdbc:mysql://10.6.112.200:3306/test?useUnicode=true&characterEncoding=UTF-8]]> 49 </property> 50 <property name="user">root</property> 51 <property name="password">5a6f38</property> 52 </named-config> 53 </c3p0-config>
3.使用的数据源类:com.mchange.v2.c3p0.ComboPooledDataSource
使用的Connection类:com.mchange.v2.c3p0.impl.NewProxyConnection
4.自定义工具类包装DataSource以简化书写
1 package day16.regular.utils; 2 /** 3 * 使用c3p0创建的连接池。 4 */ 5 import java.sql.Connection; 6 import java.sql.SQLException; 7 8 import javax.sql.DataSource; 9 10 import com.mchange.v2.c3p0.ComboPooledDataSource; 11 12 public class DataSourceUtils_C3P0 { 13 private static DataSource ds=null; 14 static{ 15 ds=new ComboPooledDataSource("namedconfig"); 16 } 17 public static Connection getConnection(){ 18 Connection conn=null; 19 try { 20 conn=ds.getConnection(); 21 } catch (SQLException e) { 22 e.printStackTrace(); 23 } 24 return conn; 25 } 26 public static DataSource getDataSource(){ 27 return ds; 28 } 29 }
5.测试代码
假设数据库连接池中最多只能有两条连接。
1 public void testC() throws SQLException 2 {
private static DataSource ds=DataSourceUtils_C3P0.getDataSource(); 3 Connection conn=ds.getConnection(); 4 // NewProxyConnection a=null; 5 System.out.println(conn); 6 Connection conn1=ds.getConnection(); 7 System.out.println(conn1); 8 9 conn1.close(); 10 Connection conn2=ds.getConnection(); 11 System.out.println(conn2); 12 }
6.运行结果:
连接池初始化信息略。 com.mchange.v2.c3p0.impl.NewProxyConnection@116d7bd [wrapping: com.mysql.jdbc.JDBC4Connection@ade3e9] com.mchange.v2.c3p0.impl.NewProxyConnection@3337df [wrapping: com.mysql.jdbc.JDBC4Connection@9920f6] com.mchange.v2.c3p0.impl.NewProxyConnection@1548499 [wrapping: com.mysql.jdbc.JDBC4Connection@9920f6]
7.c3p0总结。
(1)c3p0连接池中存放的是标准的Connection对象(实际上是JDBC4Connection对象),在分配的时候再对其进行包装。
(2)调用close方法将会销毁NewProxyConnection对象,NewProxyConnection是Connection(JDBC4Connection)的包装类。
(3)调用close方法不会销毁连接池中的对象。
也就是说c3p0的管理方式类似于卖蛋糕,平时蛋糕放在柜台中,当客人明确了想要买某个蛋糕之后服务人员才对其进行包装。