比如有乙個方法a,在a的內部有兩次同樣的select查詢,但是在兩次select之間方法b對資料庫進行了修改,那麼查詢到的a兩次查詢到的內容是否一致呢,這其實就是資料庫的 」不可重複讀/幻讀「 問題
這裡用spring+hibernate+mysql實驗,如果方法a不在事務環境下執行,那麼查詢到的兩次結果將會不同
@suppresswarnings("unchecked")
@override
public
list
getall()
可以看到斷點在第66行,這時第66行還未執行,第65行的查詢結果裡有三條記錄,如果這時資料庫被刪除了一條記錄,查詢的結果就會少一條
此時讓**執行一步就可以看見查詢結果只有兩條了
如果在事務環境裡執行,那麼修改資料庫也不會影響查詢結果
@transactional
//注意這裡加了事務的註解
這時刪除資料庫資料,或者修改資料庫資料都不會影響兩次查詢的結果的一致性
那麼這是怎麼實現的呢,mysql預設情況下乙個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。該級別可以防止髒讀和不可重複讀。
幻讀是如何防止的?mysql的innodb引擎提供的mvcc解決了幻讀問題,mvcc對不同的事務儲存了不同的資料版本
比如說有乙個**審批表,乙個欄位是**,乙個欄位是審批是否同意,員工只能修改**,領導只能對**做出審批,那就要防止領導與員工同時操作這條記錄,不然會出現領導批准了300元的**,但同時員工卻將**修改為了200元。
一共有兩種解決方案
也就是有個人訪問這一行,別人訪問就會阻塞,具體可以由lockmode這個類實現
@transactional
public void update(long id, price newprice)
大家同時可以訪問,最後只有乙個人會成功,其他人可以通過反覆重試事務來完成,這種一般是在表裡加個字段version來實現
@version
private
int version;
這裡只列出一種併發情形,領導的審批事務先執行完畢,其它與這個處理方式類似
員工事務
領導事務
開始事務
開始事務
從資料庫獲取**資訊(price:2,status:未審批,version:1)
從資料庫獲取**資訊(price:2,status:未審批,version:1)
設定審批狀態(price:2,status:已審批,version:1)
設定**(price:3,status:未審批,version:1)
開始提交事務,此時資料庫裡version為1
提交成功
(price:2,status:已審批,version:2)
開始提交事務,此時資料庫裡version為2,與自身version不同
提交失敗
提示使用者重新整理頁面
其實通過hibernate的查詢語句就能看出來原理,在update 的時候where條件後除了id外還新增了乙個version欄位,如果資料庫裡的version和和自身的不一樣,那查詢出來的結果肯定為空,這時hibernate肯定會丟擲異常,可以捕獲這個異常進行後續處理,比如提示使用者當前的資料已經不是最新的資料。
id=? and
version=?
資料庫事務與併發
資料庫事務必須具備acid特徵 1 原子性 指整個資料事務是不可分割的工作單元。只有事務中所有操作執行成功,才算整個事務成功 事務中任何乙個sql語句執行失敗,那麼已經執行成功的sql語句也必須撤銷,資料庫狀態應該退回到執行事務前的狀態。2 一致性 指資料庫事務不能破壞關係資料的完整性以及業務邏輯上...
資料庫事務併發問題
乙個資料庫可能擁有多個訪問客戶端,這些客戶端都可以併發方式訪問資料庫。資料庫中的相同資料可能同時被多個事務訪問,如果沒有採取必要的隔離措施,就會導致各種併發問題,破壞資料的完整性。這些問題可以歸結為 5類,包括 3類資料讀問題 髒讀 幻象讀和不可重複讀 以及 2類資料更新問題 第一類丟失更新和第二類...
oracle資料庫事務併發操作
1 丟失資料修改 當兩個或多個事務選擇同一行,然後基於最初選定的值更新該行時,會發生丟失更新問題。每個事務都不知道其它事務的存在。最後的更新將重寫由其它事務所做的更新,這將導致資料丟失。2 讀 髒 資料 髒讀 讀 髒 資料是指事務t1修改某一資料,並將其寫回磁碟,事務t2讀取同一資料後,t1由於某種...