數(shù)據(jù)庫(kù)連接池中的connection在八小時(shí)內(nèi)沒(méi)有被用到,則會(huì)自動(dòng)斷開(kāi)連接,那么怎么處理數(shù)據(jù)庫(kù)連接超時(shí)的問(wèn)題?
我在自己寫(xiě)mybatis框架的時(shí)候,這樣處理的:首先確保連接池中有指定數(shù)量的鏈接:將connection和創(chuàng)建時(shí)間System.currentTimeMillis()以鍵值對(duì)的形式存放在map集合中,用一個(gè)定時(shí)器,每隔1小時(shí)檢查一下連接數(shù)目,數(shù)目大于指定個(gè)數(shù),則從map中移除,小于指定個(gè)數(shù),則加入新的鏈接。其次:檢查連接在7個(gè)小時(shí)內(nèi)是否被用,如果沒(méi)有被用,則執(zhí)行一個(gè)sql語(yǔ)句:String sql = "drop table if exists tables";將connection對(duì)象重新加入到map集合中。
我的代碼:
public class ConnectionFacory{
PRivate static ConnectionFacory instance;
private static DBConn dbConn = new DBConn();//獲取鏈接的類(lèi)
private static String fileName = null;//數(shù)據(jù)庫(kù)的文件名,先為null,初始化對(duì)象后改為傳入的值
/**
* 需要知道連接池中的連接是否被使用。
* 如果用Map<Connection,time>的數(shù)據(jù)類(lèi)型去保存
* time為初始化連接的毫秒值,沒(méi)有使用過(guò)的話設(shè)置為0.
* 從數(shù)據(jù)庫(kù)獲取時(shí),設(shè)置獲取當(dāng)前的時(shí)間毫秒值。
* 并把這個(gè)連接加入到另一個(gè)連接池中
*
*/
private static Map<Connection,Long> connectionPool =new HashMap<Connection,Long>();
/**
* 設(shè)置最大時(shí)間為一個(gè)常量
*/
public static finallong MAX_UNUSED_TIME = 7 * 60 *60 * 1000;
/**
* 使用的連接都加入到這個(gè)連接池中
*/
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;//屬于共享數(shù)據(jù)
initPool(20);
timer();
}
return instance;
}
public static void initPool(int connectionCount) {
//得到connectionCount個(gè)連接,并把連接加入到連接池中
for (int i = 0; i < connectionCount; i++) {
connectionPool.put(dbConn.getConnection(fileName),System.currentTimeMillis());//添加進(jìn)來(lái)的連接都沒(méi)有使用過(guò)。
}
}
public Connection getConnection(){
Connection conn = null;
//如果connectionPool為空,說(shuō)明連接池中沒(méi)有連接,要向連接池中添加一個(gè)連接
if(connectionPool.isEmpty()){
connectionPool.put(dbConn.getConnection(fileName),System.currentTimeMillis());
}
//從連接池中獲取一個(gè)連接,獲取的時(shí)候,也獲取時(shí)間,保存到另一個(gè)連接池中
Entry<Connection, Long> en =connectionPool.entrySet().iterator().next();
conn = en.getKey();//獲取一個(gè)connection對(duì)象。
connectionPool.remove(conn);//移除con對(duì)象
return conn;
}
/*
* 設(shè)置一個(gè)定時(shí)器
* 每隔一個(gè)小時(shí)監(jiān)測(cè)一下connectionpool連接池中的連接個(gè)數(shù)
* 如果個(gè)數(shù)過(guò)少,創(chuàng)建新連接,如果個(gè)數(shù)過(guò)多,則移除連接.
* 還要保證連接是持續(xù)的,保證每8小時(shí)執(zhí)行一次sql語(yǔ)句
*/
public static void timer(){
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
//指定時(shí)間要執(zhí)行的代碼
@Override
public void run() {
int size =connectionPool.size();
/**
* 對(duì)連接池的連接進(jìn)行檢驗(yàn),小于20個(gè),則說(shuō)明連接池的數(shù)量過(guò)少,需要向里面添加新連接至20個(gè)。
* 但是正在使用的連接可能還會(huì)歸還,所以以后還可能多出來(lái)連接。所以還要檢驗(yàn)連接數(shù)量是否多余20個(gè)。
*/
if(size < 20){
for (; size < 21;size++) {
connectionPool.put(dbConn.getConnection(fileName),System.currentTimeMillis());
}
}
/**
* 因?yàn)闄z測(cè)到連接小于20個(gè)時(shí),可能有些連接正在使用,會(huì)添加連接至20個(gè)。
* 當(dāng)正在使用的連接已經(jīng)使用完了,會(huì)歸還給連接池,這是連接池的數(shù)量會(huì)多于20個(gè),所以要?jiǎng)h除多余的連接,這樣保證連接的數(shù)量動(dòng)態(tài)平衡。
* 移除時(shí)盡量移除長(zhǎng)時(shí)間不使用的連接
*
*/
if(size > 20){
for (; size < 21;size--) {
// Entry<Connection,Long> en = connectionPool.entrySet().iterator().next();
connectionPool.remove(0);//移除con對(duì)象
}
}
//鏈接8小時(shí)后就會(huì)關(guān),所以八小時(shí)內(nèi)就要使用一次,而且再次執(zhí)行會(huì)判斷用不用!
/*
* 判斷前連接是否八小時(shí)內(nèi)被執(zhí)行過(guò),
* 如果執(zhí)行過(guò),那么不用管,
* 如果沒(méi)有被執(zhí)行過(guò),那么執(zhí)行一天sql語(yǔ)句,確保連接不會(huì)關(guān)閉。
* 一個(gè)大的連接池,用來(lái)保存總的連接數(shù)。
* 將使用的連接使用時(shí),保存到另一個(gè)連接中
* 但是怎么確保連接的時(shí)間呢?
*/
//遍歷這連接池中所有的連接,查看每個(gè)連接用的時(shí)間,如果時(shí)間7個(gè)小時(shí)沒(méi)有用了,那么使用一次
/**
* 每次得到當(dāng)前時(shí)間,計(jì)算出時(shí)間差,超過(guò)7小時(shí)沒(méi)有使用,就使用一次。
*/
/*
* 定義一個(gè)Map集合,用于存放con和是否被修改的變量
* 為什么要不直接把這個(gè)connection重新加入到map中,而要重新定義這個(gè)變量?
* 因?yàn)閙ap集合在遍歷的時(shí)候不能修改集合,否則會(huì)出現(xiàn)異常。
*/
Map<Boolean,Connection>conMap = new HashMap<Boolean,Connection>();
/*
* for循環(huán)遍歷的時(shí)候不能修改集合元素的內(nèi)容。
*/
for (Entry<Connection,Long> en : connectionPool.entrySet()) {
long time =System.currentTimeMillis() - en.getValue();
Connection con =en.getKey();
if(time >MAX_UNUSED_TIME){
/**
* 執(zhí)行一個(gè)sql語(yǔ)句
*/
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);
}
}
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注