自定义连接池&C3P0&Druid

连接池

学习目标

  1. 能够理解连接池解决现状问题的原理(理解)
  2. 能够理解代理模式(不需要重点掌握)
  3. 能够使用动态代理(最好能搞懂)
  4. 能够使用C3P0连接池(必须掌握)
  5. 能够编写C3P0连接池工具类(必须掌握)
  6. 能够使用DRUID连接池(必须掌握)

第1章 自定义连接池

1.1 连接池概念

​ 我们现实生活中每日三餐。我们并不会吃一餐饭就将碗丢掉,而是吃完饭后将碗放到碗柜中,下一餐接着使用。目的是重复利用碗,我们的数据库连接也可以重复使用,可以减少数据库连接的创建次数。提高数据库连接对象的使用率。

连接池的概念: 连接池是创建和管理数据库连接的缓冲池技术。连接池就是一个容器,连接池中保存了一些数据库连接,这些连接是可以重复使用的。

1.2 没有连接池的现状之前JDBC访问数据库的步骤:

  1. 创建数据库连接运行SQL语句关闭连接
    每次数据库访问执行这样重复的动作
    在这里插入图片描述

  2. 每次创建数据库连接的问题

    • 获取数据库连接需要消耗比较多的资源,而每次操作都要重新获取新的连接对象,执行一次操作就把连接关闭,而数据库创建连接通常需要消耗相对较多的资源,创建时间也较长。这样数据库连接对象的使用率低。
    • 假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出

1.3 连接池解决现状问题的原理

  1. 连接池在初始化的时候会默认存放n个连接对象并存放到一个容器(LinkedList)中

  2. 当需要连接的时候,如果连接池中有连接就直接从连接池中获取,如果连接池中没有则新创建连接,如果连接数大于最大连接数时,如果再有请求需要获取连接则将其添加到等待队列

  3. 对于新创建的连接,一般不会直接销毁,它将被放到连接池中等待重复使用,只有当空闲超时后被释放。

  4. 对于原本就在连接池中的连接对象,用完之后直接放回连接池中

  5. 连接池中的连接数在空闲时会逐渐趋近于最小连接数(核心连接数),连接池在满载时的连接数会接近最大连接数。

在这里插入图片描述

数据库连接池相关API
​ Java为数据库连接池提供了公共的接口: javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池。

数据源(连接池)接口:javax.sql.DataSource中的方法

Connection getConnection() 
从连接池中取出一个连接。

常见的连接池: C3P0DruidDBCP

1.4自定义连接池的要求

  1. 在连接池初始化的时候默认存放n个连接对象
  2. 当需要连接时,如果连接池中有连接则直接从连接池中获取,没有则新创建
  3. 原本就在连接池中的连接,用完之后直接还回连接池中。从连接池的头部获取连接,从连接池的尾部归还连接
  4. 对于新创建的连接,用完之后直接销毁。

1.4.1自定义连接池第一个版本

  • 1.定义一个MyThreadPool类,该类有一个成员变量pool是LinkedList类型,用于存放连接对象的容器。
  • 2.该类有两个方法,分别用于获取连接对象和归还连接对象
    • 2.1. 获取连接的方法:当pool的长度大于零时从pool中获取(调用removeFirst()方法),当pool的长度小于等于零的时候,创建一个Connection对象
    • 2.2. 归还连接的方法:调用pool的addLast()方法
  • 3.该版本的缺点:如果连接不是原本就在连接池中的连接,也会归还到连接池中去,造成了连接池的体积越来越庞大,内存占用越来越多。

  • 4.解决方法:是原本就在连接池中的连接就归还到连接池中,是新创建的连接就直接销毁。

public class MyConnectionPool {
   
	private LinkedList<Connection> pool = new LinkedList<>();
	private String password = "123";
	private String user = "root";
	private String url = "jdbc:mysql://localhost:3306/day09_1";
	static{
   
		//注册驱动
		try {
   
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
   
			e.printStackTrace();
		}
	}
	public MyConnectionPool() throws SQLException{
   
		//初始化的时候,往容器中存放五个连接对象
		for(int i=0;i<5;i++){
   
			Connection conn = DriverManager.getConnection(url, user, password);
			pool.add(conn);
		}
	}
	public Connection getConnectionFromPool() throws SQLException{
   
		//从pool的头部拿连接
		//如果池子中有连接,就直接从池子中取
		Connection connection = null;
		if (pool.size() > 0) {
   
			connection = pool.removeFirst();
		}else {
   
			//池子中没有连接了
			//先等待,等待超时之后,就新创建连接
			connection = DriverManager.getConnection(url, user, password);
		}
		return connection;
	}
	public int getCount(){
   
		return pool.size();
	}
	public void addBack(Connection conn){
   
		//如果是原本就在池子中的,就归还到池子中
		//如果是新创建的连接,就直接销毁
		pool.addLast(conn);
	}
}

1.4.2自定义连接池第二个版本

    1. 自定义一个MyConnection类实现Connection接口,初始化连接池对象的时候往容器中存入n个MyConnection的对象。而新创建Connection的时候,则创建MySQL驱动中实现类的对象,这样就能区分拿个连接是新创建的或者是原本就在连接池中的了。
    1. 在归还连接的时候,使用instance of 判断如果该对象是MyConnection类型则归还到连接池中,否则直接销毁。
    1. 该版本缺点:初始化存放在连接池中MyConnection对象的方法都是空实现
    1. 解决方法:将MySQL驱动中实现类的对象传入到MyConnection类中,去帮助MyConnection类实现方法
/**
 * 优化:区分原本就在池子中的连接和新创建的连接
 *
 */
public class MyConnectionPool2 {
   
	private LinkedList<Connection> pool = new LinkedList<>();
	private String password = "123";
	private String user = "root";
	private String url = "jdbc:mysql://localhost:3306/day09_1";
	static{
   
		//注册驱动
		try {
   
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
   
			e.printStackTrace();
		}
	}
	public MyConnectionPool2() throws SQLException{
   
		//初始化的时候,往容器中存放五个连接对象------>我们自定义的MyConnection的对象
		for(int i=0;i<5;i++){
   
			Connection connection = DriverManager.getConnection(url, user, password);
			Connection conn = new MyConnection(connection);
			pool.add(conn);
		}
	}
	public Connection getConnectionFromPool() throws SQLException{
   
		//从pool的头部拿连接
		//如果池子中有连接,就直接从池子中取
		Connection connection = null;
		if (pool.size() > 0) {
   
			connection = pool.removeFirst();
		}else {
   
			//池子中没有连接了
			//先等待,等待超时之后,就新创建连接
			connection = DriverManager.getConnection(url, user, password);
		}
		return connection;
	}
	public int getCount(){
   
		return pool.size();
	}
	public void addBack(Connection conn) throws SQLException{
   
		//如果是原本就在池子中的,就归还到池子中
		//如果是新创建的连接,就直接销毁
		//判断是原本就在池子中的还是新创建的
		if (conn instanceof MyConnection) {
   
			//原本就在池子中的
			pool.addLast(conn);
		}else {
   
			//新创建的,就直接销毁
			conn.close();
		}
	}
}
public class MyConnection implements Connection{
   
	@Override
	public void close() throws SQLException {
   
		
	}
	public MyConnection() 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值