前言
本章介绍使用工厂模式+单例模式实现数据库连接池,基于池思想的各种实现我们接触的很多,如数据库连接池,redis连接池,线程池等等,在第三方框架下我们只需要书写好一下配置即可完成对池的使用。 而我们抽象出来的池一般都是为了解决频繁创建某资源而造成的服务器压力,我们将创建某资源的步骤交给池管理,我们只需要调用即可。 今天我们说的便是数据库连接池,数据库连接池中存放的都是Connection对象,所以说池对象中必然是要有一个容器来存放这些对象的,而这个容器是无界的吗?我们一般都会设置一个最大的数量,并且基于我们的服务器性能,连接池在各个服务器上的性能是不均衡的,所以我们应该有一个最大连接数并应该是手动控制,容器在池对象初始化中也是要有一个默认容量大小的。当我们的连接池运行起来之后,我们也需要设置一些连接的过期时间,当前的连接数,空闲连接数等等。 今天我们完成的数据库连接池只是一个Mini版,并没有太过复杂的属性和功能,我们就借助一下连接池基本的属性来介绍如何自己去实现一个数据库连接池。 上代码!
Pool抽象父类
package com.xzq.Cases.factory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public abstract class Pool {
public String propertiesName = "connection-INF.properties";
private static Pool instance = null;
protected int maxConnect = 100;
protected int normalConnect = 10;
protected String driverName = null;
protected Driver driver = null;
protected Pool() {
try {
init();
loadDrivers(driverName);
} catch (Exception e) {
}
}
private void init() throws IOException{
InputStream is = Pool.class.getClassLoader().getResourceAsStream(propertiesName);
Properties prop = new Properties();
prop.load(is);
this.driverName = prop.getProperty("driverName");
this.maxConnect = Integer.valueOf(prop.getProperty("maxConnect"));
this.normalConnect = Integer.valueOf(prop.getProperty("normalConnect"));
};
private void loadDrivers(String driverName) {
try {
driver=(Driver) Class.forName(driverName).newInstance();
DriverManager.registerDriver(driver);
} catch (Exception e) {
System.err.println("无法注册JDBC驱动程序:"+driverName+",错误:"+e);
}
}
public static Pool getInstance() throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {
if (instance == null) {
synchronized (Pool.class) {
if (instance == null) {
instance=(Pool)Class.forName("com.xzq.Cases.factory.Pool").newInstance();
instance.init();
}
}
}
return instance;
}
public abstract Connection getConnection();
public abstract Connection getConnection(long time);
public abstract void freeConnection(Connection conn);
public abstract int getnum();
public abstract int getnumActive();
protected synchronized void release() {
try {
DriverManager.deregisterDriver(driver);
System.out.println("撤销JDBC驱动程序" + driver.getClass().getName());
} catch (SQLException throwables) {
System.err.println("无法撤销JDBC驱动程序的注册:" + driver.getClass().getName());
}
}
}
数据库连接池实现类
package com.xzq.Cases.factory;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
@Slf4j
public final class DBConnectionPool extends Pool{
private static final Logger LOGGER = LoggerFactory.getLogger(DBConnectionPool.class);
private int checkedOut;
private Vector<Connection> freeConnections = new Vector<>();
private String userName = null;
private String passWord = null;
private String url = null;
private static int num = 0;
private static int numActive = 0;
private static DBConnectionPool pool = null;
public static synchronized DBConnectionPool getInstance() {
if (pool == null) {
pool = new DBConnectionPool();
}
return pool;
}
private DBConnectionPool() {
try {
init();
for (int i = 0; i < normalConnect; i++) {
Connection conn = newConnection();
if (conn != null) {
freeConnections.addElement(conn);
num++;
}
}
System.out.println(">>>>>>核心连接池初始化完毕,大小为" + num);
} catch (Exception e) {
e.printStackTrace();
}
}
private void init() throws IOException {
InputStream is = DBConnectionPool.class.getClassLoader().getResourceAsStream(propertiesName);
Properties prop = new Properties();
prop.load(is);
this.userName = prop.getProperty("userName");
this.passWord = prop.getProperty("passWord");
this.url = prop.getProperty("url");
this.driverName = prop.getProperty("driverName");
this.maxConnect=Integer.parseInt(prop.getProperty("maxConnect"));
this.normalConnect = Integer.parseInt(prop.getProperty("normalConnect"));
}
private Connection newConnection() {
Connection conn = null;
try {
if (userName == null) {
conn = DriverManager.getConnection(url);
}else {
conn = DriverManager.getConnection(url, userName, passWord);
}
System.out.println("连接池创建一个新的连接");
} catch (SQLException throwables) {
System.out.println("无法创建这个的URL的连接"+url);
return null;
}
return conn;
}
@Override
public synchronized Connection getConnection() {
Connection conn = null;
if (freeConnections.size() > 0) {
num--;
conn = freeConnections.firstElement();
freeConnections.removeElement(0);
System.out.println(">>>>>>>>>>>>从核心连接池中获取连接,当前连接池空余数: " + num);
try {
if (conn.isClosed()) {
System.out.println("从连接池中删除一个无效连接");
conn = getConnection();
}
} catch (SQLException throwables) {
System.out.println("从连接池中删除一个无效连接");
conn = getConnection();
}
} else if (maxConnect == 0 || checkedOut < maxConnect) {
conn = newConnection();
}
if (conn != null) {
checkedOut++;
}
numActive++;
return conn;
}
@Override
public synchronized Connection getConnection(long timeOut) {
long startTime = System.currentTimeMillis();
Connection conn;
while ((conn = getConnection()) == null) {
try {
wait(timeOut);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((System.currentTimeMillis() - startTime) >= timeOut) {
return null;
}
}
return conn;
}
@Override
protected synchronized void release() {
try {
Enumeration<Connection> allConnections = freeConnections.elements();
while (allConnections.hasMoreElements()) {
Connection connection = allConnections.nextElement();
try{
connection.close();
num--;
} catch (SQLException throwables) {
System.out.println("无法关闭连接池中的连接");
}
}
freeConnections.removeAllElements();
numActive = 0;
}finally {
super.release();
}
}
@Override
public synchronized void freeConnection(Connection conn) {
freeConnections.addElement(conn);
num++;
checkedOut--;
numActive--;
notifyAll();
System.out.println(">>>>>>>>>归还连接到连接池,现在连接池内空闲连接数为:"+num+",活动连接为:"+numActive+",正在使用的连接为;"+checkedOut);
}
@Override
public int getnum() {
return num;
}
@Override
public int getnumActive() {
return numActive;
}
}