面試官:你能說說事務的幾個特性是啥?有哪幾種隔離級別?

1、面試題

  • 事務的幾個特點是什麼?

  • 數據庫事務有哪些隔離級別?

  • MySQL的默認隔離級別?


2、面試官心裏分析

用mysql開發的三個基本面:存儲引擎、索引,然後就是事務,你必須得用事務。

因爲一個業務系統裏,肯定要加事務保證一堆關聯操作,要麼一起成功要麼一起失敗,對不對?所以這是聊數據庫必問的一個問題

最最最基本的用mysql來開發,就3點:存儲引擎(瞭解),索引(能建索引,寫的SQL都用上索引),事務(瞭解事務的隔離級別,基於spring的事務支持在代碼里加事務)

存儲引擎 -> innodb,索引,基本按照你的SQL的需求都建了索引(可能漏了部分索引忘了建),事務(@Transactional註解,對service層統一加了事務)


3、面試題剖析

3.1 事務的ACID

這個先說一下ACID,必須得知道:

(1)Atomic:原子性,就是一堆SQL,要麼一起成功,要麼都別執行,不允許某個SQL成功了,某個SQL失敗了,這就是扯淡,不是原子性。

(2)Consistency:一致性,這個是針對數據一致性來說的,就是一組SQL執行之前,數據必須是準確的,執行之後,數據也必須是準確的。別搞了半天,執行完了SQL,結果SQL對應的數據修改沒給你執行,那不是坑爹麼。

(3)Isolation:隔離性,這個就是說多個事務在跑的時候不能互相干擾,別事務A操作個數據,弄到一半兒還沒弄好呢,結果事務B來改了這個數據,導致事務A的操作出錯了,那不就搞笑了。

(4)Durability:持久性,事務成功了,就必須永久對數據的修改是有效的,別過了一會兒數據自己沒了,不見了,那就好玩兒了。


3.2 事務隔離級別

總之,面試問你事務,先聊一下ACID,然後聊聊隔離級別

(1)讀未提交,Read Uncommitted:這個很坑爹,就是說某個事務還沒提交的時候,修改的數據,就讓別的事務給讀到了,這就噁心了,很容易導致出錯的。這個也叫做髒讀。

(2)讀已提交,Read Committed(不可重複讀):這個比上面那個稍微好一點,但是一樣比較尷尬

就是說事務A在跑的時候, 先查詢了一個數據是值1,然後過了段時間,事務B把那個數據給修改了一下還提交了,此時事務A再次查詢這個數據就成了值2了,這是讀了人家事務提交的數據啊,所以是讀已提交。

這個也叫做不可重複讀,就是所謂的一個事務內對一個數據兩次讀,可能會讀到不一樣的值。如圖:

db4e87bdc3b140fd9fc7732e4232a847


(3)可重複讀,Read Repeatable:這個比上面那個再好點兒,就是說事務A在執行過程中,對某個數據的值,無論讀多少次都是值1;哪怕這個過程中事務B修改了數據的值還提交了,但是事務A讀到的還是自己事務開始時這個數據的值。如圖:

b64b228a2e524fc3ba5decbd5f148985


(4)幻讀:不可重複讀和可重複讀都是針對兩個事務同時對某條數據在修改,但是幻讀針對的是插入

比如某個事務把所有行的某個字段都修改爲了2,結果另外一個事務插入了一條數據,那個字段的值是1,然後就尷尬了。第一個事務會突然發現多出來一條數據,那個數據的字段是1。

那麼幻讀會帶來啥問題呢?因爲在此隔離級別下,例如:事務1要插入一條數據,我先查詢一下有沒有相同的數據,但是這時事務2添加了這條數據,這就會導致事務1插入失敗,並且它就算再一次查詢,也無法查詢到與其插入相沖突的數據,同時自身死活都插入不了,這就不是尷尬,而是囧了。

(5)串行化:如果要解決幻讀,就需要使用串行化級別的隔離級別,所有事務都串行起來,不允許多個事務並行操作。如圖:

2891101eef9b4c0d807232f8330fa08f


(6)MySQL的默認隔離級別是Read Repeatable,就是可重複讀,就是說每個事務都會開啓一個自己要操作的某個數據的快照,事務期間,讀到的都是這個數據的快照罷了,對一個數據的多次讀都是一樣的。

接下來我們聊下MySQL是如何實現Read Repeatable的吧,因爲一般我們都不修改這個隔離級別,但是你得清楚是怎麼回事兒,MySQL是通過MVCC機制來實現的,就是多版本併發控制,multi-version concurrency control。

當我們使用innodb存儲引擎,會在每行數據的最後加兩個隱藏列,一個保存行的創建時間,一個保存行的刪除時間,但是這兒存放的不是時間,而是事務id,事務id是mysql自己維護的自增的,全局唯一。

事務id,在mysql內部是全局唯一遞增的,事務id=1,事務id=2,事務id=3


340bb0ad2a674fc1af0bf1790a42271e


事務id=121的事務,查詢id=1的這一行的時候,一定會找到創建事務id <= 當前事務id的那一行

select * from table where id=1,就可以查到上面那一行

事務id=122的事務,將id=1的這一行給刪除了,此時就會將id=1的行的刪除事務id設置成122

事務id=121的事務,再次查詢id=1的那一行,能查到嗎?

能查到,要求創建事務id <= 當前事務id,當前事務id < 刪除事務id

事務id=121的事務,查詢id=2的那一行,查到name=李四

事務id=122的事務,將id=2的那一行的name修改成name=小李四

事務id=121的事務,查詢id=2的那一行,答案是:李四,創建事務id <= 當前事務id,當前事務id < 刪除事務id

在一個事務內查詢的時候,mysql只會查詢創建時間的事務id小於等於當前事務id的行,這樣可以確保這個行是在當前事務中創建,或者是之前創建的;

同時一個行的刪除時間的事務id要麼沒有定義(就是沒刪除),要麼是必當前事務id大(在事務開啓之後才被刪除);滿足這兩個條件的數據都會被查出來。

那麼如果某個事務執行期間,別的事務更新了一條數據呢?這個很關鍵的一個實現,其實就是在innodb中,是插入了一行記錄,然後將新插入的記錄的創建時間設置爲新的事務的id,同時將這條記錄之前的那個版本的刪除時間設置爲新的事務的id。

現在get到這個點了吧?這樣的話,你的這個事務其實對某行記錄的查詢,始終都是查找的之前的那個快照,因爲之前的那個快照的創建時間小於等於自己事務id,然後刪除時間的事務id比自己事務id大,所以這個事務運行期間,會一直讀取到這條數據的同一個版本。

記住,聊到事務隔離級別,必須把這套東西給噴出來,尤其是mvcc,說實話,市面上相當大比重的java程序員,對mvcc是不瞭解的

覺得文章不錯就給小老弟點個關注吧,更多內容陸續奉上。

最後,分享一份面試寶典《Java核心知識點整理.pdf》,覆蓋了JVM、鎖、高併發、反射、Spring原理、微服務、Zookeeper、數據庫、數據結構等等。加入我的個人粉絲羣(Java架構技術棧:644872653)獲取免費領取方式。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章