对于一个简单的数据库应用,由于对于数据库的访问不是很频繁,这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了,频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。如:外部使用者可通过getConnection方法获取连接,使用完毕后再通过releaseConnection 方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。这样带来的好处如下:
1、资源重用
数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2、更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3、统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。
自定义连接池
1 public class MyPool { 2 3 // 初始化连接数目 4 private static int init_count = 3; 5 // 最大连接数 6 private static int max_count = 6; 7 // 记录当前使用连接数 8 private static int current_count = 0; 9 // 连接池 10 private static LinkedList<Connection> pool = new LinkedList<>(); 11 12 static { 13 // 初始化连接 14 for (int i=0; i<init_count; i++){ 15 // 记录当前连接数目 16 current_count++; 17 // 创建原始的连接对象 18 Connection con = createConnection(); 19 // 把连接加入连接池 20 pool.addLast(con); 21 } 22 } 23 24 private static Connection createConnection(){ 25 try { 26 Class.forName("com.mysql.jdbc.Driver"); 27 // 原始的目标对象 28 final Connection con = DriverManager.getConnection("jdbc:mysql:///ysdrzp", "root", "root"); 29 30 // 对连接对象创建代理对象 31 Connection proxy = (Connection) Proxy.newProxyInstance( 32 con.getClass().getClassLoader(), 33 new Class[]{Connection.class}, 34 new InvocationHandler() { 35 @Override 36 public Object invoke(Object proxy, Method method, Object[] args) 37 throws Throwable { 38 // 方法返回值 39 Object result = null; 40 // 当前执行的方法的方法名 41 String methodName = method.getName(); 42 if ("close".equals(methodName)) { 43 System.out.println("begin:当前执行close方法开始!"); 44 pool.addLast(con); 45 System.out.println("end: 当前连接已经放入连接池了!"); 46 } else { 47 // 调用目标对象方法 48 result = method.invoke(con, args); 49 } 50 return result; 51 } 52 } 53 ); 54 return proxy; 55 } catch (Exception e) { 56 throw new RuntimeException(e); 57 } 58 } 59 60 public Connection getConnection(){ 61 62 if (pool.size() > 0){ 63 return pool.removeFirst(); 64 } 65 66 if (current_count < max_count) { 67 // 记录当前使用的连接数 68 current_count++; 69 // 创建连接 70 return createConnection(); 71 } 72 73 throw new RuntimeException("当前连接已经达到最大连接数目"); 74 } 75 78 public void realeaseConnection(Connection con) { 79 80 if (pool.size() < init_count){ 81 pool.addLast(con); 82 } else { 83 try { 84 current_count--; 85 con.close(); 86 } catch (SQLException e) { 87 throw new RuntimeException(e); 88 } 89 } 90 } 91 92 public static void main(String[] args) throws SQLException { 93 MyPool pool = new MyPool(); 94 System.out.println("当前连接: " + pool.current_count); 95 pool.getConnection(); 96 pool.getConnection(); 97 Connection con4 = pool.getConnection(); 98 Connection con3 = pool.getConnection(); 99 Connection con2 = pool.getConnection(); 100 Connection con1 = pool.getConnection(); 101 // 释放连接, 连接放回连接池 102 // 动态代理实现重写close()方法 103 con1.close(); 104 pool.getConnection(); 105 System.out.println("连接池:" + pool.pool.size()); 106 System.out.println("当前连接: " + pool.current_count); 107 } 108 109 }
DBCP
url=jdbc:mysql:///ysdrzp driverClassName=com.mysql.jdbc.Driver username=root password=root initialSize=3 maxActive=6 maxIdle=3000
public class DBCP { @Test public void testDbcp() throws Exception { // DBCP连接池核心类 BasicDataSource dataSouce = new BasicDataSource(); dataSouce.setUrl("jdbc:mysql:///ysdrzp"); dataSouce.setDriverClassName("com.mysql.jdbc.Driver"); dataSouce.setUsername("root"); dataSouce.setPassword("root"); dataSouce.setInitialSize(3); dataSouce.setMaxActive(6); dataSouce.setMaxIdle(3000); Connection con = dataSouce.getConnection(); con.prepareStatement("delete from admin where id=3").executeUpdate(); con.close(); } @Test public void testProp() throws Exception { Properties prop = new Properties(); InputStream inStream = DBCP.class.getResourceAsStream("/db.properties"); prop.load(inStream); DataSource dataSouce = BasicDataSourceFactory.createDataSource(prop); Connection con = dataSouce.getConnection(); con.prepareStatement("delete from admin where id=4").executeUpdate(); con.close(); } }
C3P0
1 <c3p0-config> 2 3 <default-config> 4 <property name="jdbcUrl">jdbc:mysql://localhost:3306/ysdrzp</property> 5 <property name="driverClass">com.mysql.jdbc.Driver</property> 6 <property name="user">root</property> 7 <property name="password">root</property> 8 <property name="initialPoolSize">3</property> 9 <property name="maxPoolSize">6</property> 10 <property name="maxIdleTime">1000</property> 11 </default-config> 12 13 <named-config name="dataSource"> 14 <property name="jdbcUrl">jdbc:mysql://localhost:3306/ysdrzp</property> 15 <property name="driverClass">com.mysql.jdbc.Driver</property> 16 <property name="user">root</property> 17 <property name="password">root</property> 18 <property name="initialPoolSize">3</property> 19 <property name="maxPoolSize">6</property> 20 <property name="maxIdleTime">1000</property> 21 </named-config> 22 23 </c3p0-config>
1 public class C3P0 { 2 3 @Test 4 public void testCode() throws Exception { 5 // 创建连接池核心工具类 6 ComboPooledDataSource dataSource = new ComboPooledDataSource(); 7 // 设置连接参数:url、驱动、用户密码、初始连接数、最大连接数 8 dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ysdrzp"); 9 dataSource.setDriverClass("com.mysql.jdbc.Driver"); 10 dataSource.setUser("root"); 11 dataSource.setPassword("root"); 12 dataSource.setInitialPoolSize(3); 13 dataSource.setMaxPoolSize(6); 14 dataSource.setMaxIdleTime(1000); 15 16 Connection con = dataSource.getConnection(); 17 con.prepareStatement("delete from admin where id=7").executeUpdate(); 18 con.close(); 19 } 20 21 @Test 22 public void testXML() throws Exception { 23 // 自动加载src下c3p0的配置文件【c3p0-config.xml】 24 //ComboPooledDataSource dataSource = new ComboPooledDataSource(); 25 ComboPooledDataSource dataSource = new ComboPooledDataSource("dataSource"); 26 PreparedStatement pstmt = null; 27 28 Connection con = dataSource.getConnection(); 29 for (int i=1; i<11;i++){ 30 String sql = "insert into user(name,password) values(?,?)"; 31 pstmt = con.prepareStatement(sql); 32 pstmt.setString(1, "Rose" + i); 33 pstmt.setInt(2, 1); 34 pstmt.executeUpdate(); 35 } 36 pstmt.close(); 37 con.close(); 38 } 39 }