![JAR search and dependency download from the Maven repository](/logo.png)
kim.zkp.quick.orm.connection.ConnectionPool Maven / Gradle / Ivy
/**
* Copyright (c) 2017, ZhuKaipeng 朱开鹏 ([email protected]).
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kim.zkp.quick.orm.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import kim.zkp.quick.orm.exception.ConnectionException;
import kim.zkp.quick.orm.exception.ConnectionExceptionCount;
import kim.zkp.quick.orm.monitor.MonitorSql;
public class ConnectionPool {
private static final Log log = LogFactory.get();
private JDBCConfig jdbcConfig;
private final ReentrantLock lock = new ReentrantLock(true);
private Condition get = lock.newCondition();
private final List unUsedConn = new LinkedList();
private final List usedConn = new LinkedList();
private volatile AtomicInteger connSize = new AtomicInteger(0);
/**用于处理空闲、过期连接*/
private final ScheduledExecutorService clearService = Executors.newSingleThreadScheduledExecutor();
public ConnectionPool(JDBCConfig jdbcConfig) {
this.jdbcConfig = jdbcConfig;
initConnectionPool(jdbcConfig.getInitialPoolSize());
if (jdbcConfig.getExecuteTimeMonitor()) {//开启sql执行耗时监控
MonitorSql.start(jdbcConfig.getMaxExecuteTimeFilePath());
}
}
/**
* ********************************************
* method name : initConnectionPool
* description : 初始化连接
* @return : void
* @param : @param initialSize
* modified : zhukaipeng , 2017年8月18日 下午11:45:31
* @see :
* *******************************************
*/
public void initConnectionPool(int initialSize){
lock.lock();
try {
for (int i = 0; i < initialSize; i++) {
unUsedConn.add(createConnection());
}
timerClearAllLeisureConnection();
log.info("===============Initialize DB Connection Pool SUCCESS===============");
} catch (Exception e) {
log.error("Initialize db connection error",e);
throw new ConnectionException(e);
}finally {
lock.unlock();
}
}
/**
* ********************************************
* method name : createConnection
* description : 创建新连接
* @return : Connection
* @param : @return
* modified : zhukaipeng , 2017年8月18日 下午11:45:45
* @see :
* *******************************************
*/
private Connection createConnection(){
lock.lock();
try {
Connection conn = DriverManager.getConnection(jdbcConfig.getUrl(),
jdbcConfig.getUsername(), jdbcConfig.getPassword());
connSize.incrementAndGet();
Connection qcw = new ConnectionWrapper(conn,this);
log.debug("Create db connection:{} success",qcw);
return qcw;
} catch (SQLException e) {
log.error("Create db connection error",e);
throw new ConnectionException("Create db connection error",e);
}finally{
lock.unlock();
}
}
public Connection getConnection(){
lock.lock();
try {
if (unUsedConn.size() > 0) {
Connection conn = unUsedConn.get(0);
ConnectionWrapper qcw = (ConnectionWrapper) conn;
if(qcw.isSurvive() || ConnectionExceptionCount.isClose(qcw)){
qcw.destroy();
unUsedConn.remove(conn);
connSize.decrementAndGet();
return getConnection();
}
qcw.setLastUsedTime(System.currentTimeMillis());
unUsedConn.remove(conn);
usedConn.add(conn);
return conn;
}
if (connSize.get() < jdbcConfig.getMaxPoolSize()) {
Connection conn = createConnection();
usedConn.add(conn);
return conn;
}
boolean isSignal = get.await(jdbcConfig.getMaxWaitTime(), TimeUnit.MILLISECONDS);
if (isSignal) {
return getConnection();
}
throw new ConnectionException("当前数据库连接已达上限,无法再创建连接");
} catch (Exception e) {
log.error("Get connection error",e);
throw new ConnectionException("Get connection error",e);
}finally {
lock.unlock();
}
}
public Connection getConnection(String username, String password) throws SQLException {
if (jdbcConfig.getUsername().equals(username) && jdbcConfig.getPassword().equals(password)) {
return getConnection();
}
throw new ConnectionException("Username or password error");
}
/**
* ********************************************
* method name : timerClearAllLeisureConnection
* description : 定时释放空闲链接、定时清除已使用但长时间未释放的连接
* @return : void
* @param :
* modified : zhukaipeng , 2017年8月17日 下午4:30:21
* @see :
* *******************************************
*/
public void timerClearAllLeisureConnection(){
timerClearUnUsedConnection();
timerClearUsedConnection();
}
/**
* ********************************************
* method name : timerClearUnUsedConnection
* description : 空闲连接清理
* @return : void
* @param :
* modified : zhukaipeng , 2017年8月17日 上午10:41:28
* @see :
* *******************************************
*/
public void timerClearUnUsedConnection(){
if (jdbcConfig.getIdleConnectionTestPeriod() <= 0) {
return;
}
clearService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
lock.lock();
log.debug("开始清理空闲连接。【已创建连接:{},已使用:{},空闲:{}】",connSize.get(),usedConn.size(),unUsedConn.size());
if (unUsedConn.size() <= jdbcConfig.getMinPoolSize())
return;
unUsedConn.removeIf(c -> {
if (unUsedConn.size() <= jdbcConfig.getMinPoolSize())
return false;
ConnectionWrapper qcw = (ConnectionWrapper) c;
if (getIdleTime(qcw.getLastUsedTime()) < jdbcConfig.getMaxIdleTime())
return false;
try {
qcw.destroy();
} catch (Exception e) {
log.error("关闭连接出现异常", e);
}
connSize.decrementAndGet();
get.signal();
log.debug("销毁连接:{}成功",qcw);
return true;
});
} catch (Exception e) {
log.error(e,"清理空闲连接出现异常");
}finally{
lock.unlock();
}
}
}, jdbcConfig.getIdleConnectionTestPeriod(), jdbcConfig.getIdleConnectionTestPeriod(), TimeUnit.MILLISECONDS);
}
/**
* ********************************************
* method name : timerClearUsedConnection
* description : 清理已使用但未归还连接,每五分钟执行一次,若获取连接后,过了30分钟还未归还,则关闭此连接。
* 规避连接泄露风险
* @return : void
* @param :
* modified : zhukaipeng , 2017年8月17日
* @see :
* *******************************************
*/
public void timerClearUsedConnection(){
int interval = 5*60*1000;
int idle = 30*60*1000;
clearService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
lock.lock();
log.info("开始清理已使用未归还连接。【已创建连接:{},已使用:{},空闲:{}】",connSize.get(),usedConn.size(),unUsedConn.size());
usedConn.removeIf(c -> {
ConnectionWrapper qcw = (ConnectionWrapper) c;
if (getIdleTime(qcw.getLastUsedTime()) < idle) {
return false;
}
try {
qcw.destroy();
} catch (Exception e) {
log.error("关闭连接出现异常", e);
}
connSize.decrementAndGet();
get.signal();
log.debug("销毁连接:{}成功", qcw);
return true;
});
} catch (Exception e) {
log.error(e,"清理已使用连接出现异常");
}finally{
lock.unlock();
}
}
}, interval, interval, TimeUnit.MILLISECONDS);
}
private long getIdleTime(long lastUsedTime){
return System.currentTimeMillis() - lastUsedTime;
}
public void recycleConnection(Connection conn){
lock.lock();
try {
boolean isRemove = usedConn.remove(conn);
if (isRemove) {
unUsedConn.add(conn);
get.signal();
}
// log.debug("回收连接:{}成功",conn);
// log.debug("当前连接情况【已创建:{},已使用:{},空闲:{}】",connSize.get(),usedConn.size(),unUsedConn.size());
} catch (Exception e) {
log.error("回收连接出现异常", e);
throw new ConnectionException("回收连接出现异常",e);
}finally{
lock.unlock();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy