数据库连接池
数据库连接池
实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池.
- 概念
用池来管理Connection,这样可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。池就可以再利用这个Connection对象了。
特别是在多并发,多用户的时候,更加明显。
---类似线程池 - 作用:自身维护了多个Connection连接对象维护
- 规范:
Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!(接口由数据库厂商或第三方公司实现,不用我们自己写)
常见的连接池:DBCP
、C3P0
。
自定义连接池
在javax.sql.DataSource接口--连接池的接口
- 功能:初始化多个连接.把多个连接放入到内存中.
- 归还:将连接对象放回到内存中.
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
import com.itheima.utils.JdbcUtils;
/**
* 简易的连接池
* @author Administrator
*
*/
public class MyDataSource {
static LinkedList<Connection> pool=new LinkedList<>();
//创建连接池,3个连接
static{
//初始化的时候 需要放入3个连接---用集合,经常用,link快一点
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pool.addLast(conn);//放到最后面
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//从连接池中获取连接
public static Connection getConnection(){
//获取连接的时候需要判断list是否为空
if(pool.isEmpty()){
//在添加3个连接进去
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("从池中获取一个连接");
return pool.removeFirst();//先进先出
}
//归还连接的方法
public static void addBack(Connection conn){
//将conn放入到list的最后面即可
pool.addLast(conn);
System.out.println("连接已归还");
}
}
- 使用案例:
import java.sql.Connection;
public class TestDs {
public static void main(String[] args) {
//创建连接池
MyDataSource ds = new MyDataSource();
//获取连接
Connection conn=ds.getConnection();
System.out.println(conn);
//归还连接
ds.addBack(conn);
}
}
- 存在问题:
1.创建连接池的时候能不能面向接口编程.
2.额外增加连接池的方法,那么程序员需要记住这些方法.能不能不额外去提供一些方法. - 解决:就是要去增强Connection的close方法.
- 继承的方法:
条件:能够控制这个类的构造. - ☆装饰者模式:(静态代理)
(1)使用条件:
(1.1)增强的类和被增强的类实现相同的接口.
(1.2)在增强的类中能够获得被增强的类的引用.
(2)接口中方法过多,只增强其中的一个方法.其他方法都需要原样调用原有方法.
- 继承的方法:
- ☆动态代理:
JDK的动态代理使用条件:被代理的对象必须实现接口.
使用静态代理加强连接池
//加强close方法,其他方法用之前的
import java.sql.Connection;
public class ConnectionWarp implements Connection {//继承这个接口
private Connection conn;
private LinkedList<Connection> list;
public ConnectionWarp(Connection conn){
this.conn=conn;
}
public ConnectionWarp(Connection conn,LinkedList<Connection> list){
this.conn=conn;
this.list=list;
}
@Override
//不需要加强的方法 调用原来的
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
//不需要加强的方法 调用原来的
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override
//需要加强的方法
public void close() throws SQLException {
//添加到连接池中
System.out.println("前:"+list.size());
//System.out.println(this);//this代表的是当前连接
list.addLast(this);//添加当前conncetion
System.out.println("后:"+list.size());
System.out.println("已经归还到连接池中");
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return conn.unwrap(iface);//调用原来的方法
}
- 升级的连接池工具类
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;
import com.itheima.utils.JdbcUtils;
/**
* 升级的连接池
* @author Administrator
*
*/
public class MyDataSource {
static LinkedList<Connection> pool=new LinkedList<>();
static{
//初始化的时候 需要放入3个连接
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//从连接池中获取连接
public static Connection getConnection(){
//获取连接的时候需要判断list是否为空
if(pool.isEmpty()){
//在添加2个连接进去
for (int i = 0; i < 3; i++) {
try {
Connection conn = JdbcUtils.getConnection();
pool.addLast(conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
System.out.println("从池中获取一个连接");
Connection conn = pool.removeFirst();
//将conn进行包装
// ConnectionWarp myConn = new ConnectionWarp(conn);
ConnectionWarp myConn = new ConnectionWarp(conn,pool);
return myConn;//返回的是加强的连接
}
//归还连接的方法
public static void addBack(Connection conn){
//将conn放入到list的最后面即可
pool.addLast(conn);
System.out.println("连接已归还");
}
}
- 测试:
public class TestDs {
public static void main(String[] args) throws SQLException {
//创建连接池
MyDataSource ds = new MyDataSource();//自己建立的简单连接池
//获取连接
Connection conn=ds.getConnection(); //其中的建立连接
System.out.println(conn);
//归还连接
conn.close(); //加强的close
}
}