java数据库连接池
1.基本原理
在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。如外部使用者可通过getConnection方法来获取连接,使用完毕后再同伙releaseConnection方法将连接返回,注意此时并没有关闭连接,而是由连接池管理器回收,并为下一次使用做好准备。
2.连接池的作用
1.资源重用
由于数据库连接得到重用,避免了频繁的创建、释放连接引起的大量的性能开销。在减少系统消耗的基础上,增进了系统环境的平稳性(减少内存碎片以及数据库临时进程。线程的数量)
2.更快的系统响应速度
数据库连接池在初始化线程过程中,往往已经创建了若干数据库连接置于线程池中备用。此时连接池的初始化操作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统整体响应时间。
3.新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置。实现数据库连接技术。
4.统一的连接管理,避免数据库连接泄露
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制回收被占用的连接,从而避免了常规数据库连接操作中可能出现的资源泄露。
3.基本实现思路
1.配置数据库连接池相关参数,比如数据库的连接信息,最小连接数、最大连接数等
2.初始化配置信息,创建一定数量的连接资源,并放置在一个连接池(集合),这里使用线程安全的集合来存放;
3.连接池分为两种,活跃连接池,空闲连接池,正常情况下,新来的一个连接请求,如果空闲连接池存在连接资源,直接取一个,如果不存在就新建一个。
4.如果断开某个连接,就从活跃连接池集合剔除一个,放到空闲连接池,如果空闲连接池达到了上限,即最大连接数(自定义),就关闭这个连接。
5.模拟多线程并发请求连接。
4.代码实现
1.导入jdbc驱动包
mysql,oracle都行
2.定义一个接口,获取连接和释放连接接口
package pool;
import java.sql.Connection;
public interface ConnectionService {
//获取连接(可重复复用机制)
public Connection getConnection();
//回收、释放连接(可回收机制)
public void releaseConnection(Connection connection);
}
3.配置数据库连接的基本信息,实际可以通过读取配置文件加载,这里偷懒了
package pool;
public class DbBean {
//jdbc驱动名
private String driverName = "oracle.jdbc.driver.OracleDriver";
//jdbc连接URL
private String url = "jdbc:oracle:thin:@12.15.4.241:1521:ora11g";
//数据库用户名
private String userName = "omonitor";
//数据库密码
private String password = "omonitor";
//线程池名称
private String poolName = "thread01";
//空闲池,最小连接数
private int minConnections = 1;
//空闲池,最大连接数
private int maxConnections = 10;
//初始化连接数
private int initConnections = 5;
//重复获得连接的频率
private long connTimeOut = 1000;
//最大的允许连接数,和数据库设置对应
private int maxActiveConnections = 100;
//查看数据库设置的最大连接数
//SELECT VALUE FROM v$parameter WHERE name='processes' --结果为1000
//连接超时时间,默认20分钟
private long connectionTimeOut = 1000 * 60 * 20;
//添加get/set方法,这里为了不占位置,就不贴出来了
}
4.连接池实现类,这里面主要是对具体方法的实现
package pool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;
import java.util.Vector;
public class ConnectionPool implements ConnectionService {
//池中没有使用的空闲线程,用Vector是因为它是线程安全的
private List<Connection> freeConnection = new Vector<Connection>();
//池中正在使用的线程
private List<Connection> activeConnection = new Vector<Connection>();
//配置文件,jdbc驱动,url,账号,密码等
private DbBean dbBean;
//标记创建的的连接数量
private int countConne = 0;
public ConnectionPool(DbBean dbBean) {
this.dbBean = dbBean;
init();
}
//初始化线程池
public void init() {
if (dbBean == null) {
Exception e = new NullPointerException();
e.printStackTrace();
}
//1.获取初始化连接数
for (int i = 0; i < dbBean.getInitConnections(); i++) {
//2.创建数据库连接
Connection newConnection = newConnection();
if (newConnection != null) {
//3.存放在freeConnection集合中
freeConnection.add(newConnection);
}
}
}
//创建Connection连接
public synchronized Connection newConnection() {
try {
//加载驱动
Class.forName(dbBean.getDriverName());
//获取连接
Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(), dbBean.getPassword());
//创建连接数+1
countConne++;
return connection;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//连接的获取和归还,需要使用同步代码块
@Override
public synchronized Connection getConnection() {
Connection connection = null;
try {
//判断当前创建成功的连接总数,是否达到数据库支持的最大连接数,满了使线程等待
if (countConne < dbBean.getMaxActiveConnections()) {
//如果空闲的连接数大于0,则直接从空闲的连接中取一个
if (freeConnection.size() > 0) {
//从空闲池中获得连接
connection = freeConnection.get(0);
//拿完,记得从空闲池中删除掉,代表该连接正在使用
freeConnection.remove(0);
} else {
//如果空闲的连接数为0,供不应求,则创建新的数据库连接
connection = newConnection();
//如果创建连接失败,发生日常,返回null,避免内存溢出
if(connection==null){
return null;
}
}
boolean available = isAvailable(connection);
if (available) {
activeConnection.add(connection);
//countConne++;
} else {
countConne--;
connection = getConnection();
}
} else {
//线程等待,connTimeOut配置的等待时间
wait(dbBean.getConnTimeOut());
connection = getConnection();
}
return connection;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//判断连接是否可用
public boolean isAvailable(Connection connection) {
try {
//如果连接为空,或者已经关闭了
if (connection == null || connection.isClosed()) {
return false;
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
//连接的获取和归还,需要使用同步代码块
@Override
public synchronized void releaseConnection(Connection connection) {
try {
//1.判断线程是否可用
if (isAvailable(connection)) {
//2.判断空闲线程是否已满
if (freeConnection.size() < dbBean.getMaxConnections()) {
//空闲线程没有满,将conn加入空闲集合中
freeConnection.add(connection);
} else {
//空闲线程满了,则关闭连接,释放资源
connection.close();
countConne--;
}
//将归还的连接对象从活跃的线程池中删除掉
activeConnection.remove(connection);
notifyAll();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//new ConnectionPool().init();
}
}
5.用于集中管理资源的类(相当于对外的入口)
package pool;
import java.sql.Connection;
public class ConnectionPoolManager {
//属性配置
private static DbBean dbBean = new DbBean();
//初始化连接数
private static ConnectionPool connectionPool = new ConnectionPool(dbBean);
//需要注意的是,上面的属性都是静态的,会自动加载
//获取连接(可复用机制)
public static Connection getConnection(){
Connection connection = connectionPool.getConnection();
return connection;
}
//释放连接(可回收机制)
public static void releaseConnection(Connection connection){
connectionPool.releaseConnection(connection);
}
}
6.测试类,如何调用,以及校验正确性
package pool;
import java.sql.Connection;
public class TestConnection {
public static void main(String[] args) {
for (int i = 0; i < 6; i++) {
new Thread(() -> {
for (int j = 0; j < 10; j++) {
//获得conn
Connection connection = ConnectionPoolManager.getConnection();
System.out.println(Thread.currentThread().getName() + ",connection:" + connection);
//归还连接,不一定是关闭连接
ConnectionPoolManager.releaseConnection(connection);
}
}, "线程i获取的连接;" + i).start();
}
}
}