平台的路由應用需要讀取乙個表中的記錄,優先讀取sms_id比較小的記錄;並且因為會有兩個路由應用同時工作,為避免重複讀取,需要在讀取時鎖定記錄,讀完後將這些記錄刪除;這就要用到oracle中的select for update語句;排序後的記錄無法使用for update子句;只好先用普通查詢,用order by方式查出前n條記錄的sms_id,得到結果中最大的sms_id,然後用 where sms_id <= 最大值 for update 的方式鎖定並獲取相應的記錄。
**如下:
query query = session.createquery("select s.smsid from " + entityname
+ " s order by s.smsid");
listidlist = query.setmaxresults(rownum).list();
//如果結果為空,說明表中沒有記錄,應直接返回。
if (idlist.size() == 0)
query = session.createquery("from " + entityname
+ " s where s.smsid <= ?");
query.setbigdecimal(0, idlist.get(idlist.size() - 1));
query.setlockmode("s", lockmode.upgrade);
datalist = query.list();
在本機測試,兩個應用同時開啟,都工作正常,沒有出現重複讀取的現象,也沒有出現任何異常。
部署到產品線後,兩個路由應用卻時不時丟擲deadlock異常;流量越大的時候,出現deadlock的可能性越高,在執行了幾天後的乙個下午,兩個路由應用都死掉了,導致資料大量積壓。只開乙個路由應用的話,不會出現deadlock異常。
奇怪是在本機測試時,不管壓上多少的流量,都不會出現這個異常;找資料庫的dba拿日誌,由於日誌被刪掉,不會再生成,就拿不到死鎖的日誌,dba提到可能是問題源於本機測試連的是單資料庫,而產品線上連得是採用rac的兩個資料庫,兩個資料庫操作相同的資料;在產品線上可能乙個路由通過某個資料庫鎖定記錄,而另乙個應用通過另乙個資料庫鎖定記錄,比連單資料庫的情況要複雜些;可能是這種複雜性導致本機沒有問題的操作在產品線上卻丟擲deadlock異常。
沒有拿到日誌,搞不清楚是怎麼死鎖的,只好進行嘗試;可以採取的方案的有
1. 同事提出的過濾條件不用 sms_id <= 最大值,而是用 sms_id in (),這樣也許能更精確控制鎖定的記錄;修改後的**如下
query = session.createquery("from " + entityname
+ " s where s.smsid in (:ids) ");
query.setparameterlist("ids", idlist);
query.setlockmode("s", lockmode.upgrade);
datalist = query.list()
2. 採用原生sql,在for update後面加上skip locked,這樣會話在鎖定記錄時,即使有些記錄已經被其他會話鎖定,也不會阻塞,直接跳過被鎖定的記錄,返回滿足過濾條件的未鎖定記錄;不會阻塞,應該就不會發生死鎖;修改後的**如下
string tablename = hibernatesessionfactory.gettablename(entityname);
sqlquery sqlquery = session.createsqlquery("select * from " + tablename
+ " where sms_id <= ? for update skip locked");
sqlquery.setbigdecimal(0, idlist.get(idlist.size() - 1));
sqlquery.addentity(entityname);
datalist = sqlquery.list();
先採用第乙個方案,到產品線上測試,發現兩個應用就不再丟擲deadlock異常;既然問題解決了,就沒有到產品線上測試第二個方案,畢竟產品線不是測試機。
對rac的了解不多,想不明白為什麼這麼一改就好了,先記著吧。
乙個簡單的死鎖
死鎖 當第乙個執行緒進入第乙個if進入鎖定o1鎖定o2的同步塊,第二個執行緒在外邊等待 當第乙個執行緒出來進入第二個if,第二個執行緒進第乙個if進入o1同步 塊,第乙個執行緒進入第二個if的o2同步 塊,兩個執行緒互相等待彼此釋放鎖,造成死鎖 public class diedlock imple...
乙個JAVA死鎖的Demo
死鎖的條件肯定是兩個鎖以上時,才會 發生死鎖,以下demo是模擬的兩個鎖,通過兩個執行緒分別呼叫兩個方法,這兩個方法加鎖的順序正好相反,從而造成兩個執行緒相互等待,互不釋放鎖 package com.threaddemo public class deadlocksample private voi...
舉乙個死鎖的例子
大家工作中或者面試的時候,會碰到死鎖的問題,大家都聽說過兩個執行緒互相等待,從而導致等死 鎖 的情況吧,就是執行緒1持有物件1的鎖,執行緒2持有物件2的鎖,然後兩者都等待對方釋放其持有物件的鎖,然後一直等,等到死亡。但是聽是都聽過,若有人讓你寫個例子呢?下面就舉個例子 public class di...