面試官:說說Spring中的事務(wù)傳播行為

前言

在開發(fā)中敢订,相信大家都使用過Spring的事務(wù)管理功能。那么厅缺,你是否有了解過蔬顾,Spring的事務(wù)傳播行為呢?

Spring中湘捎,有7種類型的事務(wù)傳播行為诀豁。事務(wù)傳播行為是Spring框架提供的一種事務(wù)管理方式,它不是數(shù)據(jù)庫提供的窥妇。不知道大家是否聽說過“不要在service事務(wù)方法中嵌套事務(wù)方法舷胜,這樣會提交多個事務(wù)”的說法,其實(shí)這是不準(zhǔn)確的活翩。了解了事務(wù)傳播行為之后烹骨,相信你就會明白!

原創(chuàng)聲明

本文首發(fā)于頭條號【Happyjava】材泄。Happy的掘金地址:https://juejin.im/user/5cc2895df265da03a630ddca沮焕,Happy的個人博客:(http://blog.happyjava.cn)[http://blog.happyjava.cn]。歡迎轉(zhuǎn)載拉宗,但須保留此段聲明峦树。

Spring中七種事務(wù)傳播行為

事務(wù)的傳播行為,默認(rèn)值為 Propagation.REQUIRED旦事】可以手動指定其他的事務(wù)傳播行為,如下:

  • Propagation.REQUIRED

如果當(dāng)前存在事務(wù)姐浮,則加入該事務(wù)谷遂,如果當(dāng)前不存在事務(wù),則創(chuàng)建一個新的事務(wù)单料。

  • Propagation.SUPPORTS

如果當(dāng)前存在事務(wù)埋凯,則加入該事務(wù);如果當(dāng)前不存在事務(wù)扫尖,則以非事務(wù)的方式繼續(xù)運(yùn)行白对。

  • Propagation.MANDATORY

如果當(dāng)前存在事務(wù),則加入該事務(wù)换怖;如果當(dāng)前不存在事務(wù)甩恼,則拋出異常。

  • Propagation.REQUIRES_NEW

重新創(chuàng)建一個新的事務(wù),如果當(dāng)前存在事務(wù)条摸,延緩當(dāng)前的事務(wù)悦污。

  • Propagation.NOT_SUPPORTED

以非事務(wù)的方式運(yùn)行,如果當(dāng)前存在事務(wù)钉蒲,暫停當(dāng)前的事務(wù)切端。

  • Propagation.NEVER

以非事務(wù)的方式運(yùn)行,如果當(dāng)前存在事務(wù)顷啼,則拋出異常踏枣。

  • Propagation.NESTED

如果沒有,就新建一個事務(wù)钙蒙;如果有茵瀑,就在當(dāng)前事務(wù)中嵌套其他事務(wù)。

準(zhǔn)備工作

數(shù)據(jù)庫表:

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL,
  `password` varchar(255) DEFAULT NULL,
  `username` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

一個整合了Spring Data JPA的SpringBoot工程躬厌,這里就不多說了马昨。

REQUIRED(默認(rèn)的事務(wù)傳播行為)

默認(rèn)的事務(wù)傳播行為是Propagation.REQUIRED,也就是說:如果當(dāng)前存在事務(wù)扛施,則加入該事務(wù)鸿捧,如果當(dāng)前不存在事務(wù),則創(chuàng)建一個新的事務(wù)煮嫌。

image

下面笛谦,我們就驗(yàn)證下前面說的“不要循環(huán)嵌套事務(wù)方法”的問題:

現(xiàn)在有兩個Service抱虐,如下:

UserService.java

@Service
public class UserService {

    @Autowired
    private UserRepo userRepo;

    @Transactional(propagation = Propagation.REQUIRED)
    public void insert() {
        UserEntity user = new UserEntity();
        user.setUsername("happyjava");
        user.setPassword("123456");
        userRepo.save(user);
    }


}

這里很簡單昌阿,就一個insert插入用戶的方法。

UserService2.java

@Service
public class UserService2 {

    @Autowired
    private UserService userService;


    @Transactional
    public void inserBatch() {
        for (int i = 0; i < 10; i++) {
            if (i == 9) {
                throw new RuntimeException();
            }
            userService.insert();
        }
    }

}

注入UserService恳邀,循環(huán)十次調(diào)用參數(shù)方法懦冰。并且第十次拋出異常。調(diào)用inserBatch方法谣沸,查看結(jié)果:

@Test
public void insertBatchTest() {
    userService2.inserBatch();
}

結(jié)果如下:

image

數(shù)據(jù)庫中沒有記錄:

image

這也證明了“如果當(dāng)前存在事務(wù)刷钢,則加入該事務(wù)”的概念。如果以后還碰到有人說不要循環(huán)嵌套事務(wù)的話乳附,可以叫他回去好好看看Spring的事務(wù)傳播行為内地。

SUPPORTS

如果當(dāng)前存在事務(wù),則加入該事務(wù)赋除;如果當(dāng)前不存在事務(wù)阱缓,則以非事務(wù)的方式繼續(xù)運(yùn)行。也就是說举农,該模式是否支持事務(wù)荆针,看調(diào)用它的方法是否有事務(wù)支持。測試代碼如下:

UserService

@Transactional(propagation = Propagation.SUPPORTS)
public void insert() {
    UserEntity user = new UserEntity();
    user.setUsername("happyjava");
    user.setPassword("123456");
    userRepo.save(user);
    throw new RuntimeException();
}

UserService2

public void insertWithoutTx() {
    userService.insert();
}

調(diào)用的方法沒有開啟事務(wù),運(yùn)行結(jié)果:

image
image

運(yùn)行報錯了航背,但是數(shù)據(jù)卻沒有回滾掉喉悴。說明了insert方法是沒有在事務(wù)中運(yùn)行的。

MANDATORY

如果當(dāng)前存在事務(wù)玖媚,則加入該事務(wù)箕肃;如果當(dāng)前不存在事務(wù),則拋出異常今魔。mandatory中文是強(qiáng)制性的意思突雪,表明了被修飾的方法,一定要在事務(wù)中去調(diào)用涡贱,否則會拋出異常咏删。

UserService.java

@Transactional(propagation = Propagation.MANDATORY)
public void insert() {
    UserEntity user = new UserEntity();
    user.setUsername("happyjava");
    user.setPassword("123456");
    userRepo.save(user);
}

UserService2.java

public void insertWithoutTx() {
    userService.insert();
}

調(diào)用:

@Test
public void insertWithoutTxTest() {
    userService2.insertWithoutTx();
}

運(yùn)行結(jié)果:

image

拋出了異常,提示沒有存在的事務(wù)问词。

REQUIRES_NEW

這個理解起來可能會比較繞督函,官方的解釋是這樣子的:

Create a new transaction, and suspend the current transaction if one exists.

大意就是:重新創(chuàng)建一個新的事務(wù),如果當(dāng)前存在事務(wù)激挪,延緩當(dāng)前的事務(wù)辰狡。這個延緩,或者說掛起垄分,可能理解起來比較難宛篇,下面通過例子來分析:

UserService.java

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insert() {
    UserEntity user = new UserEntity();
    user.setUsername("happyjava");
    user.setPassword("123456");
    userRepo.save(user);
}

這個insert方法的傳播行為改為REQUIRES_NEW。

UserService2.java

@Transactional
public void inserBatch() {
    UserEntity user = new UserEntity();
    user.setUsername("初次調(diào)用");
    user.setPassword("123456");
    userRepo.save(user);
    for (int i = 0; i < 10; i++) {
        if (i == 9) {
            throw new RuntimeException();
        }
        userService.insert();
    }
}

inserBatch擁有事務(wù)薄湿,然后后面循環(huán)調(diào)用的insert方法也有自己的事務(wù)叫倍。根據(jù)定義,inserBatch的事務(wù)會被延緩豺瘤。具體表現(xiàn)就是:后面的10次循環(huán)的事務(wù)在每次循環(huán)結(jié)束之后都會提交自己的事務(wù)吆倦,而inserBatch的事務(wù),要等循環(huán)方法走完之后再提交坐求。但由于第10次循環(huán)會拋出異常蚕泽,則inserBatch的事務(wù)會回滾,既數(shù)據(jù)庫中不會存在:“初次調(diào)用”的記錄:

測試代碼:

@Test
public void insertBatchTest() {
    userService2.inserBatch();
}

執(zhí)行結(jié)果:

image
image

這種情況桥嗤,符合開始說的“不要循環(huán)嵌套事務(wù)方法”的說話须妻,當(dāng)然是否需要循環(huán)嵌套,還是要看業(yè)務(wù)邏輯的泛领。

NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists.

以非事務(wù)的方式運(yùn)行荒吏,如果當(dāng)前存在事務(wù),暫停當(dāng)前的事務(wù)师逸。這種方式與REQUIRES_NEW有所類似司倚,但是NOT_SUPPORTED修飾的方法其本身是沒有事務(wù)的豆混。這里就不做代碼演示了。

NEVER

以非事務(wù)的方式運(yùn)行动知,如果當(dāng)前存在事務(wù)皿伺,則拋出異常。

@Transactional(propagation = Propagation.NEVER)
public void insert() {
    UserEntity user = new UserEntity();
    user.setUsername("happyjava");
    user.setPassword("123456");
    userRepo.save(user);
}

@Transactional
public void insertWithTx() {
    userService.insert();
}

執(zhí)行結(jié)果:

image

NESTED

如果沒有事務(wù)盒粮,就新建一個事務(wù)鸵鸥;如果有,就在當(dāng)前事務(wù)中嵌套其他事務(wù)丹皱。

這個也是理解起來比較費(fèi)勁的一個行為妒穴。我們一步一步分析。

外圍方法沒有事務(wù):這種情況跟REQUIRED是一樣的摊崭,會新建一個事務(wù)讼油。

外圍方法如果存在事務(wù):這種情況就會嵌套事務(wù)。所謂嵌套事務(wù)呢簸,大意就是矮台,外圍事務(wù)回滾,內(nèi)嵌事務(wù)一定回滾根时,而內(nèi)嵌事務(wù)可以單獨(dú)回滾而不影響外圍主事務(wù)和其他子事務(wù)瘦赫。

由于本人使用Spring Data JPA 進(jìn)行的演示代碼,使用嵌套事務(wù)會提示:

org.springframework.transaction.NestedTransactionNotSupportedException: JpaDialect does not support savepoints - check your JPA provider's capabilities

搜索了下蛤迎,hibernate似乎不支持這種事務(wù)傳播方式确虱。所以這里就不做演示了

總結(jié)

事務(wù)傳播行為,在開發(fā)中可能不會特別的留意到它(更多時候替裆,我們可能只是使用默認(rèn)的方式)校辩,但是還是需要對其要有所理解。希望本篇文章能讓大家明白Spring的7種事務(wù)傳播行為扎唾。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末召川,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子胸遇,更是在濱河造成了極大的恐慌,老刑警劉巖汉形,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纸镊,死亡現(xiàn)場離奇詭異,居然都是意外死亡概疆,警方通過查閱死者的電腦和手機(jī)逗威,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岔冀,“玉大人凯旭,你說我怎么就攤上這事。” “怎么了罐呼?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵鞠柄,是天一觀的道長。 經(jīng)常有香客問我嫉柴,道長厌杜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任计螺,我火速辦了婚禮夯尽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘登馒。我一直安慰自己匙握,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布陈轿。 她就那樣靜靜地躺著肺孤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪济欢。 梳的紋絲不亂的頭發(fā)上赠堵,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機(jī)與錄音法褥,去河邊找鬼茫叭。 笑死,一個胖子當(dāng)著我的面吹牛半等,可吹牛的內(nèi)容都是我干的揍愁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼杀饵,長吁一口氣:“原來是場噩夢啊……” “哼莽囤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起切距,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤朽缎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谜悟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體话肖,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年葡幸,在試婚紗的時候發(fā)現(xiàn)自己被綠了最筒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蔚叨,死狀恐怖床蜘,靈堂內(nèi)的尸體忽然破棺而出辙培,到底是詐尸還是另有隱情,我是刑警寧澤邢锯,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布扬蕊,位于F島的核電站,受9級特大地震影響弹囚,放射性物質(zhì)發(fā)生泄漏厨相。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一鸥鹉、第九天 我趴在偏房一處隱蔽的房頂上張望蛮穿。 院中可真熱鬧,春花似錦毁渗、人聲如沸践磅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽府适。三九已至,卻和暖如春肺樟,著一層夾襖步出監(jiān)牢的瞬間檐春,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工么伯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疟暖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓田柔,卻偏偏與公主長得像俐巴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子硬爆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1.DAO和事務(wù)管理的牽絆 事務(wù)管理的目的是保證數(shù)據(jù)操作的事務(wù)性(原子性欣舵、一致性、隔離性缀磕、持久性缘圈,即所謂的ACID...
    小螺釘12138閱讀 491評論 1 2
  • 事務(wù),是為了保障邏輯處理的原子性虐骑、一致性准验、隔離性、永久性廷没。 通過事務(wù)控制,可以避免因?yàn)檫壿嬏幚硎《鴮?dǎo)致產(chǎn)生臟數(shù)據(jù)...
    uzip柚子皮閱讀 4,618評論 3 16
  • Spring 事務(wù)屬性分析 事務(wù)管理對于企業(yè)應(yīng)用而言至關(guān)重要垂寥。它保證了用戶的每一次操作都是可靠的颠黎,即便出現(xiàn)了異常的...
    壹點(diǎn)零閱讀 1,305評論 0 2
  • 第十五章 話說這牛魔王原本是通天教主的坐騎另锋,奎牛。 封神大劫之后狭归,截教落敗夭坪。萬仙來朝之勢也煙消云散。牛魔王逃過一劫...
    七生在閱讀 232評論 0 0
  • 2017-6-29 星期四 天氣晴 寶貝年齡:7周歲3個月和1周5個月 學(xué)經(jīng)周期:3年半 學(xué)經(jīng)人員:琦琦过椎,琦媽室梅。 ...
    廈門琦心媽閱讀 147評論 0 2