赞
踩
数据库连接池负责分配、管理和释放数据库连接,它允许应程序重复使用一个现有的数据库连接,而不是再重新建立一个。
创建一个DbConfig类在其中进行数据库连接池的基础配置
public class DbConfig { public static final String driverName = "com.mysql.jdbc.Driver"; //jdbc驱动 public static final String url = "jdbc:mysql://localhost:3306/"; //本地数据库接口 public static final String userName = "root"; //账号 public static final String password = "password"; //密码 public static final int maxConnections = 10; // 空闲池,最大连接数 public static final int initConnections = 5;// 初始化连接数 public static final long connTimeOut = 1000;// 重复获得连接的频率 public static final int maxActiveConnections = 100;// 最大允许的连接数,和数据库相匹配 public static final long connectionTimeOut = 1000 * 60 * 20;// 连接超时时间,这里为20分钟 }
千万别忘了添加数据库驱动文件,如图,不然程序跑不起来
创建一个连接池工具接口ConnectionPool
import java.sql.Connection;
public interface ConnectionPool {
//获取连接
public Connection getConnection();
//销毁连接
public void releaseConnection(Connection connection);
}
实现该接口
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.Vector; import java.util.concurrent.atomic.AtomicInteger; public class ConnectionPoolImpl implements ConnectionPool { // 空闲连接池 private List<Connection> freeConnection = new Vector<Connection>(); // 活动连接池 private List<ConnectionInfo> activeConnection = new Vector<ConnectionInfo>(); //当前连接数 private AtomicInteger countConne = new AtomicInteger(0); //初始化 public ConnectionPoolImpl() { init(); } private void init() { //初始化连接放到空闲连接池中 if (DbConfig.initConnections > 0) { for (int i = 0; i < DbConfig.initConnections; i++) { //加入连接到空闲连接池中 AddOneConnectToFree(); } } } private void check() { TimeCheck timeCheck = new TimeCheck(); // 延迟一个重复获得连接的频率开始检查,每一个重复获得连接的频率检查一次 new Timer().schedule(timeCheck,Long.valueOf(DbConfig.connTimeOut),Long.valueOf(DbConfig.connTimeOut)); } class TimeCheck extends TimerTask { public void run() { System.out.println("例行检查..."); for (int i = 0; i < activeConnection.size(); i++) { ConnectionInfo info = activeConnection.get(i); // 连接获取时间(加入到活动连接池的时间) long startTime = info.getUseStartTime(); // 获取系统当前时间 long currentTime = System.currentTimeMillis(); try { if ((currentTime - startTime) > Long.valueOf(DbConfig.connectionTimeOut)) { Connection conn = info.getConn(); if (conn != null && !conn.isClosed()) { // 关闭连接 conn.close(); // 从活动连接池中移出 activeConnection.remove(i); // 总连接数变化 countConne.decrementAndGet(); System.out.println("发现有超时连接强行关闭," + conn + ",空闲连接数:" + freeConnection.size() + "," + "在使用连接数:" + activeConnection.size() + ",总的连接数:" + countConne.get()); } } } catch (SQLException e) { e.printStackTrace(); } finally { } } } } // 向空闲连接池中加入连接 private void AddOneConnectToFree(){ Connection connection = newConnection(); if (connection!=null){ // 连接可用,向空闲连接池中加入连接 freeConnection.add(connection); }else { // 连接不可用,递归尝试 AddOneConnectToFree(); } } // 新建连接 private Connection newConnection(){ try{ Class.forName(DbConfig.driverName); Connection connection = DriverManager.getConnection(DbConfig.url,DbConfig.userName,DbConfig.password); System.out.println("创建一个新的连接:"+connection); return connection; }catch (Exception e){ e.printStackTrace(); } return null; } // 获取连接 public synchronized Connection getConnection() { try{ Connection connection = null; // 判断是否大于最大连接数 if (countConne.get() < DbConfig.maxActiveConnections){ // 判断空闲连接池是否有对象 if (freeConnection.size() > 0){ // 有对象时从空闲连接池中获取一个连接 connection = freeConnection.remove(0); }else { // 没有对象时新建连接 connection = newConnection(); } // 对象可用 if (connection != null && !connection.isClosed()){ // 将连接对象加入到活动连接池中 activeConnection.add(new ConnectionInfo(connection,System.currentTimeMillis())); // 总连接数改变 countConne.getAndIncrement(); System.out.println(Thread.currentThread().getName() + ",获取并使用连接:" + connection + ",空闲连接数:" + freeConnection.size() + "," + "活动连接数:" + activeConnection.size() + ",总的连接数:" + countConne.get()); }else { //如果对象不可用,递归重试 connection = getConnection(); } }else { System.out.println(Thread.currentThread().getName() + ",连接池最大连接数为:" + DbConfig.maxConnections + "已经满了,需要等待..."); //当达到最大连接时,等待后重试 wait(DbConfig.connTimeOut); connection = getConnection(); } return connection; }catch (Exception e){ e.printStackTrace(); } return null; } //释放连接 public synchronized void releaseConnection(Connection connection) { try{ if (connection != null && !connection.isClosed()){ // 从活动连接池中移出 for (int i = 0; i < activeConnection.size(); i++) { if (activeConnection.get(i).getConn() == connection) { activeConnection.remove(i); } } //判断空闲容器是否达到最大连接 if (freeConnection.size() < DbConfig.maxConnections){ //小于最大连接,则添加到空闲容器中 freeConnection.add(connection); }else { //大于最大连接直接关闭 connection.close(); } // 总连接数改变 countConne.getAndDecrement(); } System.out.println("回收了一个连接:" + connection + ",空闲连接数为:" + freeConnection.size() + ",活动连接数为:" + activeConnection.size()); // 唤醒其它线程 notifyAll(); }catch (Exception e){ e.printStackTrace(); } } }
活动连接池中存放的ConnectionInfo类代码
import java.sql.Connection; public class ConnectionInfo { private Connection conn; private long useStartTime; //开始使用时间 public Connection getConn() { return conn; } public void setConn(Connection conn) { this.conn = conn; } public long getUseStartTime() { return useStartTime; } public void setUseStartTime(long useStartTime) { this.useStartTime = useStartTime; } public ConnectionInfo(Connection conn, long useStartTime) { super(); this.conn = conn; this.useStartTime = useStartTime; } }
import java.sql.Connection; public class Test { public static void main(String[] args) { // 创建连接池 ConnectionPool connectionPool = new ConnectionPoolImpl(); // 利用线程模拟获取连接 for (int i = 0; i <= 10000; i++) { new Thread(()->{ for (int j=0;j<6;j++){ Connection connection = connectionPool.getConnection(); connectionPool.releaseConnection(connection); } }).start(); } } }
开始
结束
为了呈现效果,我将连接池的连接数限制的更小。出现接池已满的现象
由于模拟的线程释放连接十分迅速,所以看不到超时的现象。
更改的配置
public static final int maxConnections = 5; // 空闲池,最大连接数
public static final int initConnections = 3;// 初始化连接数
public static final int maxActiveConnections = 10;// 最大允许的连接数
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。