這幾天面試多次被問到了資料庫事務機制、隔離級別、樂觀鎖悲觀鎖類的問題,之前對這些只能說有所了解,有些概念還停留在記憶層面,沒有理解,所以回答的不好,后面翻書學習了下,理解了一些東西,在此做一個記錄, 什么是事務? 事務我理解的是一個完整的業務行為,一個業務行為可能包含多個動作,這個完整的動作就構成一個事務,比較經典的例子是銀行轉賬,A賬戶轉到B賬戶,需要兩個動作:A賬戶減,B賬戶加,必須保證這兩個動作要么都做,要么都不做, 事務具有ACID特征,具體包括:
- 原子性(atomicity):原子性是說事務的不可分割,要么全成功,要么全失敗,不可部分成功,部分失敗,半途失敗的情況下,需要打掃戰場,也就是資料回滾,
- 一致性(consistency):一致性是說事務的最后結果,要保證資料上沒有例外,一致性是強調結果,是建立在原子性上實作的,也就是說能保證原子性,那就會有一致性的結果,
- 隔離性(isolation):隔離性是說事務沒有提交前對其他事務是不可見的,事務間資料是隔離的(當然不同級別隔離程度不一樣),
- 持久性(durability): 事務提交后會持久化,可以長久保存,
- 臟讀:就是讀到了別人還沒提交的資料,
- 可重復讀:就是同一個事物內的兩次查詢,中間如果別人修改了查詢內的記錄且提交了,對第二次查詢是不可見的,不會出現同條記錄兩次查詢不一致問題,
- 幻讀:就是一個事物內的兩次查詢,中間如果別人增加了記錄并且提交了,第二次查詢能查詢到的,會出現和第一次記錄不一致的現象,
- 讀未提交:這種級別是最低的,A事務的修改沒有提交對B事物是可見的,會出現資料的臟讀,一般情況下不會用到此種型別,
- 讀已提交:A事物的修改提交后才對B可見,這種情況會出現資料的幻讀的問題,兩次查詢的結果不一樣,
- 可重復讀:是MySQL默認的級別,這種級別事物內的兩次查詢,中間其他修改了某條記錄,對其他事務是不可見的,保證了重復查的情況下同條記錄的一致性,但是對于新增的情況其他事務是可見的,所以還是會出現新增幻讀的現象,
- 可串行化:事務之間是串行執行的,對查詢到的每條記錄都加鎖,會出現阻塞的情況,并發情況下會造成嚴重的性能問題,所以一般也不會用到這種型別,
- 查詢時:查詢當前事務之前存在的記錄和本事務創建的記錄,且沒有被洗掉的,即:創建版本號<=當前版本號 && (洗掉版本號為空 || 洗掉版本號 > 當前版本號)
- 插入時:記錄的創建版本號為當前事務版本號,
- 洗掉時:更新記錄的洗掉版本號為當前事務版本號,
- 更新時:插入一條新記錄,創建版本號為當前事務版本號,同時把原記錄洗掉版本號改為當前事務版本號,代表已經洗掉,實際上這里的更新相當于洗掉再加一條記錄,
- 悲觀鎖可以在資料庫層面很簡單的解決,利用select ... for update,在查詢的時候就鎖定這部分資料,
- 樂觀鎖的實作較悲觀鎖復雜,可以在資料庫在一個版本號的列,更新的時候版本號都+1,以此來確認我查出來的資料后面有沒有別人修改,已修改的不更新或程式拋一個例外,
使用樂觀鎖還是悲觀鎖: 從性能的角度考慮樂觀鎖性能更好,在查詢到更新這段時間沒有鎖定操作,但是實作起來沒有悲觀鎖簡單,可能出錯,所以要考慮的因素是系統的并發高不高?出現沖突的概率有多大?并發高的情況下選用樂觀鎖更好,反之選用悲觀鎖這種簡單的方式更好,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/70583.html
標籤:MySQL
