上週五,一同事在開發時遇到了一個問題,叫我幫忙看下.在描述這個同事遇到問題以前,我先簡單作一些知識的鋪墊,不然很差描述.這裏面涉及到的知識點有Spring的事務傳播機制
、數據庫的隔離級別
等.面試
本篇重點是解決同事遇到的問題,由於這兩個知識點都先簡單談談,只爲引出主題.後面這兩個會專門用一篇來說sql
Sring的事務傳播機制有七種,本文涉及到的有兩種數據庫
REQUIRED
: 用得最多(估計高達90%),也是默認的模式.若當前沒有事務,則新建事務,若當前已存在一個事務, 則加入到該事務中緩存
REQUIRES_NEW
: 新建一個事務bash
Spring的事務傳播機制.後面我會用一篇文章專門來說,給你們列各類典型的題型,按照高中的題型訓練模式,完全弄懂Spring的傳播機制,即便在各類複雜嵌套
+ try
場景下也能雲淡風輕地肯定回滾狀況.包括解析以前很是經典的一道面試題mybatis
考慮到部分同窗英文問題,我特地標記了中文性能
1.Read Uncommitted
: 讀未提交spa
這個基本不可能用,從字面意思你就知道了,讀到別人還未提交的數據,別人都沒提交,你怎麼知作別人接下來是要提交仍是回滾?既然不知道你就讀,天然會有問題.這個問題就是咱們說的髒讀
.debug
2.Serializable
: 串行化3d
其實就是同步化,性能太差,基本不可能用這個.可是這個是惟一能解決幻讀
問題的.
剩下兩種隔離級別
Read Committed
: 讀已提交
Read Repeatable
: 可重複讀
就比較重要了,咱們畫圖來分析
好比我問,當t4
時,查詢出來的數據,name是大肥朝
仍是toby
.其實你心裏就不是很肯定了,可是我若是把提交事務
這幾個字加粗標紅,而後引誘一下,絕大多數同窗根本把持不住!!!
既然都提交事務
了,那讀出來的天然是toby
啦.
其實t4
讀出來是toby
仍是大肥朝
這個取決與你用的是讀已提交
、可重複讀
.其實你從這個中文名稱均可以猜到了,若是是讀已提交
,那麼查出來的就是toby
.若是是可重複讀
.讀出來的天然就是大肥朝
. MySQL
默認用的是可重複讀
.Oracle
默認用的是讀已提交
.
舒適提示: 這個後面也能夠考慮再寫一篇詳細講一下這個隔離級別,由於通常問到可重複讀
,有深度的面試官會繼續追問,可重複讀是如何實現的?具體怎麼實現的咱們能夠先關注肥朝公衆號,後面再具體說數據庫的MVCC
機制
因爲業務具備必定的複雜度,不利於你們觀看,所以我這裏特地抽象簡化了模型.
首先,我先把數據庫的隔離級別改爲讀已提交
.截圖爲證:
那麼問題來了,請問步驟3查詢出來的數據是什麼呢.咱們一塊兒來見證
1.查詢完數據,準備更新數據
2.更新完成提交了事務,咱們看得出此時數據庫已經改爲了toby
3.震驚!查出來的數據居然是大肥朝
這個時候彷佛就不厚道了,肥朝你前面怎麼說的,你前面說讀已提交
讀出來的是別人已經提交的,那麼應該是toby
纔對啊,怎麼仍是大肥朝
?.
咱們把配置文件設置成`debug級別一切就豁然開朗了
logging.level.com.toby.demo.dao=debug
logging.level.org.mybatis=debug
複製代碼
這裏我特地用不一樣顏色給你們標記清楚了,其實看到只輸出兩次SQL
日誌你們就知道了.第三次查詢沒有輸出SQL,這很明顯是用到了Mybatis
的緩存了.再根據我標記的SqlSession
信息來看,這裏就是用到了Mybatis
的一級緩存
解決辦法有不少,咱們知道Mybatis一級緩存的做用域是SqlSession
,那麼只要兩次查詢是不一樣的SqlSession
那天然這個一級緩存就失效了.一級緩存失效了.就會查詢兩次,輸出兩次sql.這個時候是toby
仍是大肥朝
就真的取決於我前面說的隔離級別
了.好比一個簡單的改法是
改法有不少,具體根據那麼的業務來就能夠了,固然也能夠採用上面那種
肥朝 是一個專一於 原理、源碼、開發技巧的技術公衆號,號內原創專題式源碼解析、真實場景源碼原理實戰(重點)。掃描下面二維碼關注肥朝,讓本該造火箭的你,再也不擰螺絲!