一文讀懂Spring的事務(wù)機(jī)制
Spring框架是日常開(kāi)發(fā)中必定會(huì)用到的框架,而它的事務(wù)機(jī)制,也是面試的重中之重,今天我們來(lái)討論一下Spring的事務(wù)機(jī)制。
什么是事務(wù)
廚房沒(méi)有醬油了,媽媽叫你去商店買一瓶回來(lái)。買醬油的過(guò)程,你給分成三個(gè)步驟:
1.去媽媽那拿錢
2.去商店挑好醬油
3.把錢給收銀員
這3個(gè)步驟,只要其中一個(gè)步驟完不成,買醬油失敗。只有全部完成,買醬油成功。這種一組操作,要么全部成功,要么全部不成功,就叫做事務(wù)。
什么是Spring事務(wù)
Spring支持聲明式事務(wù)和編程式事務(wù)兩種方式。
1.聲明式事務(wù)
在SpringBoot中可以在方法上添加@Transanal注解來(lái)實(shí)現(xiàn)

@Transanal注解參數(shù)分為以下幾種方式:
REQUIRED:如果沒(méi)有事務(wù)就新建一個(gè)事務(wù),否則就加入已有事務(wù),是默認(rèn)的事務(wù)機(jī)制
REQUIRES_NEW:不管有沒(méi)有事務(wù),都新建一個(gè)事務(wù)。例子事務(wù)A下面有個(gè)事務(wù)B,事務(wù)A的回滾不會(huì)影響事務(wù)B,導(dǎo)致事務(wù)B回滾
NESTED:如果外層沒(méi)有事務(wù)就新建一個(gè)事務(wù),如果外層有事務(wù)就嵌入其他事務(wù),事務(wù)A下面有事務(wù)B。如果事務(wù)A回滾,事務(wù)B也會(huì)回滾,但是事務(wù)B回滾不會(huì)影響事務(wù)A。
SUPPORTS:如果當(dāng)前存在一個(gè)事務(wù),則加入到該事務(wù)中;如果不存在事務(wù),則不使用事務(wù)。這種傳播行為通常用于測(cè)試場(chǎng)景。
MANDATORY:必須在一個(gè)事務(wù)中執(zhí)行此操作,如果當(dāng)前沒(méi)有事務(wù),則拋出異常。
NEVER:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在一個(gè)事務(wù),則拋出異常。
NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在一個(gè)事務(wù),則掛起該事務(wù)。
2.編程式事務(wù)
聲明式事務(wù)非常簡(jiǎn)單,方法上加一個(gè)注解就能搞定,但是它的范圍太大了。如果你只是想要對(duì)方法中的某一段代碼做事務(wù)處理,不想上升到整個(gè)方法,那么可以采用編程式事務(wù)。

Spring事務(wù)的陷阱

上面是一個(gè)Spring事務(wù)方法,先插入一條數(shù)據(jù),然后異步從數(shù)據(jù)庫(kù)查詢出來(lái),打印日志。但是實(shí)際場(chǎng)景跑的時(shí)候,你會(huì)發(fā)現(xiàn),日志很有可能不會(huì)打印。
這是為什么呢?
因?yàn)锧Transactional注解的方法,是要把方法里面的所有代碼執(zhí)行完畢,才會(huì)提交到數(shù)據(jù)庫(kù)。也就是說(shuō)實(shí)際的執(zhí)行順序可能是這樣:
1.CustomerFollowUpRecordrecord=customerMapperExt.getByFsUserId(insertRecord);
2.customerMapperExt.insert(record);
這也是之前有個(gè)同事寫的代碼,看不出問(wèn)題,然后我?guī)兔戳讼拢l(fā)現(xiàn)的。所以要注意Spring事務(wù)的陷阱,代碼的書寫順序,不代表執(zhí)行順序。