兩個執行緒基於同乙個查詢結果進行修改,後修改的人會將先修改人的修改覆蓋掉.
讓我們先來看這麼個小案例:
我們給遊戲充值100,支付成功後,銀行會向遊戲伺服器傳送支付成功資訊,有乙個訂單支付資訊表(order)和乙個賬戶資訊表(account),首先要去order表中查詢該訂單支付狀態state(select state from order where id=1)如果是0未支付,接下來要做的就是更新state為已支付,並且向你的賬戶account中加上100. 但是網路是有延遲的銀行為了確保資訊能送達可能會再次向伺服器傳送支付成功資訊。這時第二次請求也是先去查詢state,若此次請求和第一次正好是併發執行,他查詢到的state也是0,所以也會給你的account加100塊錢。也就是後來的修改覆蓋掉了前邊的修改,這就是資料丟失。
操作流程如下:
先來看一下資料庫中的鎖機制:
共享鎖:在非serializable隔離級別做查詢不加任何鎖,而在serializable隔離級別下做的查詢加共享鎖,
共享鎖的特點:共享鎖和共享鎖可以共存,但是共享鎖和排他鎖不能共存
排他鎖:在所有隔離級別下進行增刪改的操作都會加排他鎖,
排他鎖的特點:和任意其他鎖都不能共存
悲觀鎖悲觀鎖悲觀的認為每一次操作都會造成更新丟失問題,在每次查詢時就加上排他鎖。
select state from order for update
這樣第二個請求在查詢時發現已經有個排他鎖,就在那等著,等第乙個事務操作完成後才輪到他,不過此時state已經變成1已支付,這樣就避免再次加100塊。
樂觀鎖會樂觀的認為每次查詢都不會造成更新丟失.利用乙個版本字段進行控制。
為order表加乙個欄位version
第一次請求查詢出未支付後,在加100塊錢之前,將更新state操作修改為:
update order set state=1 and version =version+1 where id=1 and version=0
這樣第二個請求也執行這句是version就不是0了,執行失敗。從而也防止了第一次資料的丟失。
資料庫 資料丟失問題 及解決方案
兩個執行緒基於同乙個查詢結果進行修改,後修改的人會將先修改人的修改覆蓋掉.讓我們先來看這麼個小案例 我們給遊戲充值100,支付成功後,銀行會向遊戲伺服器傳送支付成功資訊,有乙個訂單支付資訊表 order 和乙個賬戶資訊表 account 首先要去order表中查詢該訂單支付狀態state selec...
資料庫亂碼解決方案
oracle 資料庫亂碼解決方案 你插入資料的時候,用 轉變字串的亂碼函式 param str return public string getstr string str catch exception e 向bean裡面賦值 public void setaction string action...
資料庫死鎖解決方案
一 活鎖 如果事務t1封鎖了資料r,事務t2又請求封鎖r,於是t2等待。t3也請求封鎖r,當t1釋放了r上的封鎖之後系統首先批准了t3的請求,t2仍然等待。然後t4又請求封鎖r,當t3釋放了r上的封鎖之後系統又批准了t4的請求,t2有可能永遠等待,這就是活鎖的情形。避免活鎖的簡單方法是採用先來先服務...