数据库连接池中的connection在八小时内没有被用到,则会自动断开连接,那么怎么处理数据库连接超时的问题?
我在自己写mybatis框架的时候,这样处理的:首先确保连接池中有指定数量的链接:将connection和创建时间System.currentTimeMillis()以键值对的形式存放在map集合中,用一个定时器,每隔1小时检查一下连接数目,数目大于指定个数,则从map中移除,小于指定个数,则加入新的链接。其次:检查连接在7个小时内是否被用,如果没有被用,则执行一个sql语句:String sql = "drop table if exists tables";将connection对象重新加入到map集合中。
我的代码:
public class ConnectionFacory{
PRivate static ConnectionFacory instance;
private static DBConn dbConn = new DBConn();//获取链接的类
private static String fileName = null;//数据库的文件名,先为null,初始化对象后改为传入的值
/**
* 需要知道连接池中的连接是否被使用。
* 如果用Map<Connection,time>的数据类型去保存
* time为初始化连接的毫秒值,没有使用过的话设置为0.
* 从数据库获取时,设置获取当前的时间毫秒值。
* 并把这个连接加入到另一个连接池中
*
*/
private static Map<Connection,Long> connectionPool =new HashMap<Connection,Long>();
/**
* 设置最大时间为一个常量
*/
public static finallong MAX_UNUSED_TIME = 7 * 60 *60 * 1000;
/**
* 使用的连接都加入到这个连接池中
*/
private static Map<Connection,Long> connectionUsePool= new HashMap<Connection,Long>();
private ConnectionFacory(){
}
public static synchronized ConnectionFacorygetInstance(String fileName){
if(instance == null){
instance = new ConnectionFacory();
ConnectionFacory.fileName = fileName;//属于共享数据
initPool(20);
timer();
}
return instance;
}
public static void initPool(int connectionCount) {
//得到connectionCount个连接,并把连接加入到连接池中
for (int i = 0; i < connectionCount; i++) {
connectionPool.put(dbConn.getConnection(fileName),System.currentTimeMillis());//添加进来的连接都没有使用过。
}
}
public Connection getConnection(){
Connection conn = null;
//如果connectionPool为空,说明连接池中没有连接,要向连接池中添加一个连接
if(connectionPool.isEmpty()){
connectionPool.put(dbConn.getConnection(fileName),System.currentTimeMillis());
}
//从连接池中获取一个连接,获取的时候,也获取时间,保存到另一个连接池中
Entry<Connection, Long> en =connectionPool.entrySet().iterator().next();
conn = en.getKey();//获取一个connection对象。
connectionPool.remove(conn);//移除con对象
return conn;
}
/*
* 设置一个定时器
* 每隔一个小时监测一下connectionpool连接池中的连接个数
* 如果个数过少,创建新连接,如果个数过多,则移除连接.
* 还要保证连接是持续的,保证每8小时执行一次sql语句
*/
public static void timer(){
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
//指定时间要执行的代码
@Override
public void run() {
int size =connectionPool.size();
/**
* 对连接池的连接进行检验,小于20个,则说明连接池的数量过少,需要向里面添加新连接至20个。
* 但是正在使用的连接可能还会归还,所以以后还可能多出来连接。所以还要检验连接数量是否多余20个。
*/
if(size < 20){
for (; size < 21;size++) {
connectionPool.put(dbConn.getConnection(fileName),System.currentTimeMillis());
}
}
/**
* 因为检测到连接小于20个时,可能有些连接正在使用,会添加连接至20个。
* 当正在使用的连接已经使用完了,会归还给连接池,这是连接池的数量会多于20个,所以要删除多余的连接,这样保证连接的数量动态平衡。
* 移除时尽量移除长时间不使用的连接
*
*/
if(size > 20){
for (; size < 21;size--) {
// Entry<Connection,Long> en = connectionPool.entrySet().iterator().next();
connectionPool.remove(0);//移除con对象
}
}
//链接8小时后就会关,所以八小时内就要使用一次,而且再次执行会判断用不用!
/*
* 判断前连接是否八小时内被执行过,
* 如果执行过,那么不用管,
* 如果没有被执行过,那么执行一天sql语句,确保连接不会关闭。
* 一个大的连接池,用来保存总的连接数。
* 将使用的连接使用时,保存到另一个连接中
* 但是怎么确保连接的时间呢?
*/
//遍历这连接池中所有的连接,查看每个连接用的时间,如果时间7个小时没有用了,那么使用一次
/**
* 每次得到当前时间,计算出时间差,超过7小时没有使用,就使用一次。
*/
/*
* 定义一个Map集合,用于存放con和是否被修改的变量
* 为什么要不直接把这个connection重新加入到map中,而要重新定义这个变量?
* 因为map集合在遍历的时候不能修改集合,否则会出现异常。
*/
Map<Boolean,Connection>conMap = new HashMap<Boolean,Connection>();
/*
* for循环遍历的时候不能修改集合元素的内容。
*/
for (Entry<Connection,Long> en : connectionPool.entrySet()) {
long time =System.currentTimeMillis() - en.getValue();
Connection con =en.getKey();
if(time >MAX_UNUSED_TIME){
/**
* 执行一个sql语句
*/
String sql ="drop table if exists tables";
try {
con.prepareStatement(sql).execute();
conMap.put(true,con);
} catch(SQLException e) {
thrownew RuntimeException("run sql fail!");
}
}
conMap.put(false,con);
}
/*
* 遍历conMap,如果是false那么取得con,再次存入ConnectionPool中
*/
for (Entry<Boolean, Connection>en : conMap.entrySet()) {
if(en.getKey()){
connectionPool.put(en.getValue(),System.currentTimeMillis());
}
}
}
}, 0, 60 * 1000);
}
}
新闻热点
疑难解答