首先推荐一篇不错的文章。https://www.cnblogs.com/newpanderking/p/3875749.html
接下来,看了这篇文章之后,我们再看一下
1.首先是连接池的规范
/**
* 连接池 顶级规范
*/
public interface IPool {
/**
* 获取连接
*/
MyConn getConnection();
}
/**
* 定义了一定规范的抽象类
*/
/**
*
* 连接池 超类:用以提供部分规范
*/
public abstract class BasePool implements IPool{
protected String jdbcDriver;
protected String dbUrl;
protected String dbUsername;
protected String dbPassword;
protected int maxConnnect;
protected int initedConnect;
protected List<MyConn> conns;
public BasePool(String jdbcDriver, String dbUrl, String dbUsername, String dbPassword, int maxConnnect,int firstInit){
//我本来要放弃这个初始化参数:int firstInit。
//其本来是决定new多少个connection,来减少启动的消耗。
//因为第一次优化后产生的bug主要是在于多线程下init<max时,生成了更多的连接导致的问题。
//但是我看见阿里的druid都有这个参数,
//就尝试了一下将createConn(int)这个方法加上锁(synchronized)或者lock都可以。
//这个地方其实应该也可以采用volatile关键字
//但是其实createConn(int)这个方法应该竞争并没有那么激烈,不用强行在这个地方追求极致的效率
this.jdbcDriver = jdbcDriver;
this.dbUrl = dbUrl;
this.dbUsername = dbUsername;
this.dbPassword = dbPassword;
this.maxConnnect = maxConnnect;
//是为了保证线程安全。但是这样做,效率会降低很多,后续想个方式来处理
//哈哈 解决了,但是还是把最初的版本放在这里
//conns=new Vector<>(new MyConn[initedConnect]);
conns=new ArrayList<>(maxConnnect);
//创建池
initPool(firstInit);
//创建守护线程
new Thread(new GuardConnection(this,4)).start();;
}
protected void initPool(int initedConnect) {
try {
Class.forName(jdbcDriver);
createConnections(initedConnect);
}catch (Exception e) {
throw new RuntimeException("创建数据库连接出错");
}
}
protected void createConnections(int count) {
for (int i = 0; i < count; i++) {
// 大于最大连接数的话就不创建了
if (initedConnect + 1 > maxConnnect)
return;
if (count <= 0)
throw new RuntimeException("初始化连接数不能为空");
try {
Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
conns.add(new MyConn(conn, false));
// 已加载的连接数量++
initedConnect++;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public abstract List<MyConn> getConns();
}
/**
* 连接池实例
*/
public class MyPool extends BasePool {
public MyPool(String jdbcDriver, String dbUrl, String dbUsername, String dbPassword, int maxConnnect, int initedConnect) {
super(jdbcDriver, dbUrl, dbUsername, dbPassword, maxConnnect, initedConnect);
}
@Override
public MyConn getConnection() {
// 判断是否加载
if (initedConnect == 0) {
System.out.println("连接池中还没有连接!");
throw new RuntimeException("连接池中还没有连接!");
}
/**
* (1)当还有可用连接的时候
* (2)可用连接不够了,需要创建或者等待
*/
MyConn conn = getActiveConnection();
// (2)的情况
while (null == conn) {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
//创建连接
createConnections(1);
conn = getActiveConnection();
}
return conn;
}
/**
* 从集合中得到连接
*
* @return
* @return
*/
private MyConn getActiveConnection() {
for (int i = 0; i < conns.size(); i++) {
MyConn conn = conns.get(i);
if(conn.setBusy(true)) {
conn.setUseTime(System.currentTimeMillis());
return conn;
}
}
return null;
}
@Override
public List<MyConn> getConns() {
return super.conns;
}
}
2.connection的包装对象
/**
* 包含conn的对象
*/
public class MyConn {
/**
* 实际connection
*/
private Connection conn;
/**
* 是否正在工作
* 刚创建时,默认是false。
* volatile关键字,是为了提高效率,将数组的锁定放在了每一个元素的锁定
* 就有点类似与conCurrentHashMap。
* 后面发现即使使用了volatile关键字还是会存在问题。
* 因此后面还是使用了synchronized关键字来控制,但是即使如此,还是讲粒度放在了每个元素上。
* 从而提高了性能
*/
private volatile boolean isBusy=false;
/**
* 开始使用的时间:用于守护线程去强制回收
*/
private long useTime;
/**
* 查询
* @param sql
* @return
*/
public ResultSet query(String sql) {
Statement sm = null;
ResultSet rs = null;
try {
sm = conn.createStatement();
rs = sm.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
/**
* 修改操作
* @param sql
* @return
*/
public int update(String sql) {
Statement sm = null;
int count = -1;
try {
sm = conn.createStatement();
count = sm.executeUpdate(sql);
}
catch (SQLException e) {
e.printStackTrace();
}
return count;
}
public boolean isBusy() {
return isBusy;
}
/**
* 当传入的是true的时候,说明,准备占用
* 但是外面用的list不安全,因此考虑在set层操作,
* 这里的返回值是为了确定获取成功
*/
public boolean setBusy(boolean isBusy) {
//本来if else这种东西应该抽象出来,但是目前先这样吧
synchronized(this) {
if(isBusy) {
if(this.isBusy) {
return !isBusy;
}
}
//false的时候无所谓(后面思考是否会有线程安全的问题)
this.isBusy=isBusy;
return isBusy;
}
}
public void close() {
this.isBusy=false;
}
public MyConn(Connection conn, boolean isBusy) {
super();
this.conn = conn;
this.isBusy = isBusy;
}
public long getUseTime() {
return useTime;
}
public void setUseTime(long useTime) {
this.useTime = useTime;
}
public void rollback() throws SQLException {
conn.rollback();
}
}
3.守护线程
/**
* connection守护线程
*/
public class GuardConnection implements Runnable{
private BasePool pool;
private long time;
@Override
public void run() {
while(true) {
for(int i=0;i<pool.getConns().size();i++) {
MyConn conn = pool.getConns().get(i);
if(conn.isBusy() && System.currentTimeMillis() - conn.getUseTime() > time*1000 ) {
try {
conn.rollback();
}catch (Exception e) {
}finally {
conn.close();
}
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
}
public GuardConnection(BasePool pool,long time) {
super();
this.pool = pool;
this.time=time;
}
}
这样就能够完成一个简单的连接池。但是还有很多东西没有考虑。后面慢慢更新,一步步优化,加上功能:例如connection的守护线程,强制回池,性能等方面的。
---------------------------------------------------------------------------------------------------------------------------------------
目前,强制回池,守护线程都已经做到了,性能方面,经过测试,确实是有所提升。但是还是存在一些不足,例如可供拓展的一些AOP功能等等。后续考虑一下