Ibatis批處理SqlMapClient使用不關閉,資源耗盡,死鎖錯誤!
今天做OA的及時訊息通訊的---訊息快取方式實現.
因為要求快取訊息,傳送到伺服器的訊息並不會立即持久化到資料庫中,我做的是,當快取的訊息達到一定的數目的時候,啟動持久化執行緒,進行持久化,持久化是用Ibatis寫的一個方法:如下:
publicvoid insertMEG2REV(Hashtable messagequeue, Vector receiverqueue) throws MessageErrorException, SQLException{SqlMapClient sqlmap=(SqlMapClient)ServiceLocator.findMyBean(
sqlmap.startBatch();
Enumeration em=messagequeue.elements();
//插入及時訊息
while(em.hasMoreElements()){
Message message=(Message)em.nextElement();
Object Key=sqlmap.insert("MessageDao.insertNewMessage3",message);
//插入接收資訊
int REVSIZE=receiverqueue.size();
for(int i=0;i<REVSIZE;i++){
Receiver re=(Receiver)receiverqueue.get(i);
// System.out.println("----"+re.getMessage().getPrimaryKey()+" asa "+re.getPrimaryKey()+" "+re.getAffirmtime());
// if(re.getAffirmtime()==null)
if(re.getAffirmtime()==null)
sqlmap.insert("ReceiveDao.insertNewReceive2",re);
else
sqlmap.insert("ReceiveDao.insertNewReceive3",re);
}
sqlmap.executeBatch();
}
當持久化閥值比較小的時候,就會生成很多個持久化執行緒,但是他們並不是一生成就啟動,而是按照生成的先後順序來啟動,這是為了保證在插入資料時,不會產生沒有外來鍵依賴的異常!一個執行緒接一個執行緒的啟動,如果前面的執行緒,沒有完成,後面的執行緒必須等待.這是用連表的方式實現的.
由於上面所說,當持久化執行緒一多,頻繁啟動執行緒,呼叫上面的程式碼,把資料插入資料庫~問題來了,一般在啟動100多次執行緒後,伺服器死鎖了,這個時候的症狀是:CPU利用率為0(表示並不是計算量太大造成),其餘任何WEB服務不能訪問,除了JSP頁面會很慢的響應外.其餘幾乎不能響應了.
如果我沒猜錯的話,死鎖了???執行緒太多,但他們並沒有啟動啊!,不存線上程競爭資源而死鎖.
後來我懷疑是批處理的程式碼有問題,修改如下:
publicvoid insertMEG2REV(Hashtable messagequeue, Vector receiverqueue) throws MessageErrorException, SQLException{SqlMapClient sqlmap=(SqlMapClient)ServiceLocator.findMyBean("sqlMapClient");
try{
sqlmap.startTransaction();
sqlmap.startBatch();
Enumeration em=messagequeue.elements();
//插入及時訊息
while(em.hasMoreElements()){
Message message=(Message)em.nextElement();
Object Key=sqlmap.insert("MessageDao.insertNewMessage3",message);
}
//插入接收資訊
int REVSIZE=receiverqueue.size();
for(int i=0;i<REVSIZE;i++){
Receiver re=(Receiver)receiverqueue.get(i);
// System.out.println("----"+re.getMessage().getPrimaryKey()+" asa "+re.getPrimaryKey()+" "+re.getAffirmtime());
// if(re.getAffirmtime()==null)
if(re.getAffirmtime()==null)
sqlmap.insert("ReceiveDao.insertNewReceive2",re);
else
sqlmap.insert("ReceiveDao.insertNewReceive3",re);
}
sqlmap.executeBatch();
}catch(Exception e){
thrownew MessageErrorException("插入訊息和接收人 執行緒 失敗--"+tools.millsTODateString(System.currentTimeMillis()));
}finally{
sqlmap.commitTransaction();
sqlmap.endTransaction();
}
}
這次與上面的程式碼明顯不同的是: 增加了事務的管理.在最後要結束SqlMapClient.
原來我不加事務的管理的意思是:儘可能地把資料插入資料庫,如果產生異常,也不至於這次批處理完全回滾.
看來我錯了,事務管理不僅僅涉及到事務的管理,還關係到資料庫資源的獲取的釋放!
加上事務管理後,程式執行正常,不再死鎖!!!!!!!!!
由此看來,並不是死鎖,是因為你沒有釋放連線,導致資料庫資源耗盡.
所以你在使用別的WEB服務,特別是需要連線資料庫的WEB服務時,它取不到資料庫連線,它就會等待,等待有可用的連線可以獲得的時候,呼叫堆疊才會執行下去.這就造成了上面描述的現象:CPU利用率為0,但是卻不響應,原因是它在等待資料庫連線的獲得,JSP頁面能正常訪問,原因是該JSP頁面不涉及到資料庫操作.所以能正常訪問