1. 程式人生 > >Ibatis批處理SqlMapClient使用不關閉,資源耗盡,死鎖錯誤!

Ibatis批處理SqlMapClient使用不關閉,資源耗盡,死鎖錯誤!

 今天做OA的及時訊息通訊的---訊息快取方式實現.

因為要求快取訊息,傳送到伺服器的訊息並不會立即持久化到資料庫中,我做的是,當快取的訊息達到一定的數目的時候,啟動持久化執行緒,進行持久化,持久化是用Ibatis寫的一個方法:如下:

publicvoid insertMEG2REV(Hashtable messagequeue, Vector receiverqueue) throws MessageErrorException, SQLException{
        SqlMapClient sqlmap
=(SqlMapClient)ServiceLocator.findMyBean(
"sqlMapClient");
        
                    
            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頁面不涉及到資料庫操作.所以能正常訪問