c3p0数据库连接池实现原理笔记
来源:互联网 发布:java udp编程 编辑:程序博客网 时间:2024/06/06 02:24
为什么用连接池
-我们最初jdbc连接数据库需要
1. 安装驱动
2. 取得连接
3. 打开窗口
4. 书写语句、执行语句和查看结果
5. 关闭到数据库的连接
其中1,2和5完全可以重用,这样就加快了执行。也即:
同一个连接可以打开多个窗口
同一个窗口可以多次执行语句
我们发现jdbc连接数据库时对于同一个项目来说,如果每次操作数据库的话,每一次查询添加…,使用上面的方法就是要建立多次数据库连接,而每一次获得连接对于Java代码来说都是重复动作,不仅占用了空间,而且在执行效率上也产生了浪费
- 解决连接重用的方案分析
我们想象火车站售票大厅的情况,平时客流比较少时,我们只开几个售票窗口,不管有没有顾客来买票:多时间处于空闲状态。在如节假日等高峰期,所有售票窗口都会启用。特别地,在春运这样的最高峰期,可能会有临时窗口。但临时窗口也不是无限制地多开,开窗口要耗费物力人力。这样在高峰期只能让客户等待长一点的时间。春运最高峰时排队,这个时间客户就需要等待。
我们在重用数据库连接时也可以采用类似的方案。我们先打开一批连接等待客户使用(如同非高峰期我们开几个窗口) ,不管用没有客户使用。在高峰期到来时,我们可以多开几个连接让浏览器客户使用。如同春运一样不可能为了让每个人都有一个窗口服务,我们的数据库连接也不能无限开启(数据库连接要占用内存等资源,同时每个数据库能支持的并发连接数也不是无限的).在不能为需要的数据的客户立马服务时,只能让客户排队等待。如果用户一直无法得到一个连接对象时,就不要让用户无限期等待。
从上面可以看出,我们重用连接的方案,需要提供以下信息:- 预先开启的连接数
- 能开启的最大连接数
- 一个连接要被多个客户使用,因而连接用完不能关闭
- 一个超时时间,如果超过这个时间,用户就无法获取连接而得到数据。
在JDBC连接数据库的连接重用方案里,我们称为连接池。
连接池中可以重用的包括Connection对象和Statement对象
连接池的作用及原理
1. 预先开启的连接数
2. 能开启的最大连接数
3. 一个连接要被多个客户使用,因而连接用完不能关闭
4. 一个超时时间,如果超过这个时间,用户就无法获取连接而得到数据。
自定义连接池
原理
定义一个集合来保存一定数量的connection连接
重写Connection的close方法—不真正关闭而是把它放置到连接池中
- 导入相关jar包
-这里使用的是Oracle数据库我们就导入ojdbc6.jar - jdbc.properties配置文件
-url=jdbc:oracle:thin:@localhost:1521:orcl
user=lgh
password=lgh
className=oracle.jdbc.OracleDriver - 编写数据库连接工具类
package com.jt.demo07;import java.io.IOException;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Properties;/** * 数据库连接工具类 * 此类主要是加载驱动创建连接 * */public class JDBCUnti { private static String url = null; private static String user = null; private static String password = null; private static String className = null; private static Properties into = new Properties(); static { try { // 读取文件和类在一起就用该方法 into.load(JDBCUnti.class.getResourceAsStream("jdbc.properties")); url = into.getProperty("url"); user = into.getProperty("user"); password = into.getProperty("password"); className = into.getProperty("className"); } catch (IOException e) { e.printStackTrace(); } } static { try { // DriverManager.registerDriver(new OracleDriver()); // 这种注册方式实际上注册了两次驱动 Class.forName(className); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } public static void free(Statement stmt, Connection conn) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } public static void free(ResultSet res, Statement stmt, Connection conn) { if (res != null) { try { res.close(); } catch (SQLException e) { e.printStackTrace(); } } free(stmt, conn); }}
编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
Connection getConnection()Connection getConnection(String username, String password)
实现DataSource接口,并实现连接池功能的步骤:
在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到List中,而不要把conn还给数据库。Collection保证将自己返回到List中是此处编程的难点。
package com.jt.demo07;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.SQLException;import java.sql.SQLFeatureNotSupportedException;import java.util.ArrayList;import java.util.List;import java.util.logging.Logger;import javax.sql.DataSource; /** * List 集合模拟一个池子 存放lianjie * 静态代码块在类被加载时就获得执行 * 预期存入5个数据库连接 * */public class MyDatasource implements DataSource { public static List<Connection> pool = new ArrayList<Connection>(); static{ for(int i=0;i<5;i++){ try { pool.add(JDBCUnti.getConnection()); } catch (SQLException e) { e.printStackTrace(); } } } @Override public PrintWriter getLogWriter() throws SQLException { // TODO Auto-generated method stub return null; } @Override public void setLogWriter(PrintWriter out) throws SQLException { // TODO Auto-generated method stub } @Override public void setLoginTimeout(int seconds) throws SQLException { // TODO Auto-generated method stub } @Override public int getLoginTimeout() throws SQLException { // TODO Auto-generated method stub return 0; } @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { // TODO Auto-generated method stub return null; } @Override public <T> T unwrap(Class<T> iface) throws SQLException { // TODO Auto-generated method stub return null; } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { // TODO Auto-generated method stub return false; } @Override public Connection getConnection() throws SQLException { if(pool.size()>0){ final Connection conn = pool.remove(0); System.out.println("conn de ++++"+conn.getClass()); return (Connection)Proxy.newProxyInstance(null, new Class[]{Connection.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//这是一个方法内部类 通过动态代理的方法来实现对 Connection的close方法的//重写,以达到调用close方法不会关闭连接,而是把它放到连接池中 System.out.println("_____"+this.getClass()); if(method.getName().equals("close")){ System.out.println("aaaaaaaa"+this.getClass()); pool.add(conn); }else{ return method.invoke(conn, args); } return null; } }); } return null; } @Override public Connection getConnection(String username, String password) throws SQLException { // TODO Auto-generated method stub return null; }}
编写Java程序测试
编写查询数据库操作代码
package com.jt.demo07;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import oracle.jdbc.OracleDriver;public class JdbcSelect { /** * 测试MyDatasource连接池 * * */ public static void main(String[] args) throws SQLException { Connection conn = null; Statement stmt = null; ResultSet res = null; MyDatasource md = new MyDatasource(); try { conn = md.getConnection(); stmt = conn.createStatement(); String sql = "select * from t_user"; res = stmt.executeQuery(sql); System.out.println("id\tname\tpwd\tage\tbirthday"); while (res.next()) { System.out.println(res.getInt("id") + "\t" + res.getString("name") + "\t" + res.getString("pwd") + "\t" + res.getInt("age") + "\t" + res.getDate("birthday")); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUnti.free(res, stmt, conn); } }}
执行程序
第一次写博客,没什么经验,主要是想把学习的内容写出来,做个总结,有什么不足之处还请谅解
0 0
- c3p0数据库连接池实现原理笔记
- c3p0-数据库连接池原理
- c3p0(数据库连接池)私人学习笔记
- Java c3p0 oracle 数据库连接池 代码实现
- 单例模式实现C3P0数据库连接池
- 使用c3p0-0.9.2实现数据库连接池
- 数据库连接池实现原理
- 数据库连接池实现原理
- 数据库连接池实现原理
- c3p0 数据库连接池配置
- 数据库连接池C3P0 小结
- 数据库连接池 c3p0
- c3p0数据库连接池dbutil
- 数据库连接池-C3P0
- c3p0数据库连接池实例
- 数据库连接池C3P0学习
- java c3p0数据库连接池
- C3P0数据库连接池源代码
- Zxing3.x的简单使用(一)
- Mapreduce 通俗版
- SDUT 2608
- Django快速搭建web
- poj 2752 Seek the Name, Seek the Fame(KMP)
- c3p0数据库连接池实现原理笔记
- Oj:ytu2671:Problem C: 大小写英文字母转换(1)
- ubuntu 14.04 mysql change datadir
- Ruby基础教程(三)——类和模块
- hdoj5676ztr loves lucky numbers
- 写单机看看 简单的splite3
- 使用FormData对包含文件类型的form表单进行异步提交(文件上传)并配置回调
- UVa 221 Urban Elevations
- 谈谈墨迹天气app v5.8.4的用户体验1