Spring系列之事物是如何管理的

前言

我們都知道Spring給我們提供了很多抽象器躏,比如我們?cè)诓僮鲾?shù)據(jù)庫的過程中,它為我們提供了事物方面的抽象,讓我們可以非常方便的以事物方式操作數(shù)據(jù)庫褒傅。不管你用JDBC、Mybatis袄友、Hibernate等任何一種方式操作數(shù)據(jù)庫殿托,也不管你使用DataSource還是JTA的事物,Spring事物抽象管理都能很好的把他統(tǒng)一在一起剧蚣。接下來看一下事物的抽象核心接口

Spring事務(wù)抽象

PlatformTransactionManager是事物管理器接口

//事務(wù)管理器接口有以下幾個(gè)接口支竹,獲取事物信息,提交和回滾
public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}

常見的事物管理器有以下幾種:

  • DataSourceTransactionManager
  • HibernateTransactionManager
  • JtaTransactionManager
    這些管理器都實(shí)現(xiàn)了PlatformTransactionManager中的三個(gè)接口券敌,實(shí)現(xiàn)邏輯略有差別唾戚,但是對(duì)用戶來講區(qū)別不大

定義事物的一些參數(shù):
一些事物的參數(shù)在TransactionDefinition.java中,詳情如下:

public interface TransactionDefinition {
      int PROPAGATION_REQUIRED = 0;
    int PROPAGATION_SUPPORTS = 1;
    int PROPAGATION_MANDATORY = 2;
    int PROPAGATION_REQUIRES_NEW = 3;
    int PROPAGATION_NOT_SUPPORTED = 4;
    int PROPAGATION_NEVER = 5;
    int PROPAGATION_NESTED = 6;
        //默認(rèn)隔離級(jí)別待诅,和數(shù)據(jù)庫的隔離級(jí)別一致
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
        //默認(rèn)不超時(shí)
    int TIMEOUT_DEFAULT = -1;
}

下面兩張圖對(duì)這些參數(shù)進(jìn)行了說明:
7種事務(wù)傳播特性:

file

四種事務(wù)隔離級(jí)別:
在看事務(wù)隔離級(jí)別前需要先了解下什么是臟讀叹坦、不可重復(fù)讀、幻讀
臟讀: 臟讀就是一個(gè)事物未提交的數(shù)據(jù)卑雁,被另外一個(gè)事物讀到了募书,顯然這種情況不可接受
不可重復(fù)讀: 不可重復(fù)讀是指在一個(gè)事務(wù)內(nèi)绪囱,多次讀同一數(shù)據(jù),前后讀取的結(jié)果不一致莹捡。
幻讀: 事務(wù)A對(duì)表中的一個(gè)數(shù)據(jù)進(jìn)行了修改鬼吵,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí)事務(wù)B也修改了這個(gè)表中的數(shù)據(jù)篮赢,這種修改是向表中插入一行新數(shù)據(jù)齿椅。那么就會(huì)發(fā)生操作事務(wù)A的用戶發(fā)現(xiàn)表中還存在沒有修改的數(shù)據(jù)行,就好像發(fā)生了幻覺一樣
知道了以上幾個(gè)概念启泣,我們來看看隔離級(jí)別:
file

這里我們可以看到涣脚,Spring并不是提供了所有的事物管理的實(shí)現(xiàn),而是提供了標(biāo)準(zhǔn)的事物管理器的操作接口PlatformTransactionManager寥茫, 并且規(guī)范了其行為遣蚀,具體的事物實(shí)現(xiàn)由各個(gè)平臺(tái)自行實(shí)現(xiàn)。這就是Spring的事物抽象纱耻。

Spring之編程式事物

Spring提供了TransactionTemplate工具類可以很方便的使用編程式事務(wù)芭梯。默認(rèn)情況下TransactionTemplate使用的是DataSourceTransactionManager。
在Spring上下文中弄喘,我們不配置TransactionTemplate這個(gè)bean玖喘,也能獲取到TransactionTemplate。比如下面的例子限次。

@Service
public class UserInfoService {

    @Resource
    private UserInfoDAO userInfoDAO;
    @Autowired
    private TransactionTemplate transactionTemplate;
    
    public void updateUser1(){
        transactionTemplate.execute(transactionStatus -> {
            userInfoDAO.updateUserName(1,"zhangsanfeng");
            transactionTemplate.execute(transactionStatus2 -> {
                userInfoDAO.updateUserName(2,"lisi");
                return null;
            });
            return null;
        });
    }
}

由于Spring默認(rèn)的事物傳播特性是PROPAGATION_REQUIRED芒涡,我們來做一下驗(yàn)證,看是不是這樣

file

file

上面兩幅圖可以看出卖漫,TransactionStatus中的newTransaction屬性费尽,第一個(gè)是true,第二個(gè)是false羊始,正好符合PROPAGATION_REQUIRED所描述的情況旱幼。其他的傳播特性可以自己去驗(yàn)證。

聲明式事物

除了編程式事物外突委,Spring還為我們提供了聲明式事物柏卤。使用@Transactional注解。
@Transactional 可以作用于接口匀油、接口方法缘缚、類以及類方法上。當(dāng)作用于類上時(shí)敌蚜,該類的所有 public 方法將都具有該類型的事務(wù)屬性桥滨,同時(shí),我們也可以在方法級(jí)別使用該注解來覆蓋類級(jí)別的定義。

雖然 @Transactional 注解可以作用于接口齐媒、接口方法蒲每、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解喻括,因?yàn)檫@只有在使用基于接口的代理時(shí)它才會(huì)生效邀杏。另外, @Transactional 注解應(yīng)該只被應(yīng)用到 public 方法上唬血,這是由 Spring AOP 的本質(zhì)決定的望蜡。如果你在 protected、private 或者默認(rèn)可見性的方法上使用 @Transactional 注解拷恨,這將被忽略泣特,也不會(huì)拋出任何異常。

@Transactional的rollbackFor屬性可以設(shè)置一個(gè) Throwable 的數(shù)組挑随,用來表明如果方法拋出這些異常,則進(jìn)行事務(wù)回滾勒叠。默認(rèn)情況下如果不配置rollbackFor屬性兜挨,那么事務(wù)只會(huì)在遇到RuntimeException的時(shí)候才會(huì)回滾。
下面的代碼事物就不會(huì)生效:

    @Transactional
    public void updateUser2() throws Exception {
        int r1 = userInfoDAO.updateUserName(1,"wanger");
        int r2 = userInfoDAO.updateUserName(2,"mawu");
        if (r2==1){
            throw new Exception();
        }
    }

如果我們把拋出的異常改成RuntimeException眯分,這時(shí)候事物就會(huì)生效了拌汇。或者指定異常讓事物生效弊决,比如 @Transactional(rollbackFor = Exception.class),這樣碰到所有的異常事物都會(huì)生效了噪舀。

為什么加了@Transactional注解事物就生效了?

這是因?yàn)镾pring容器會(huì)為加了這個(gè)注解的對(duì)象生成一個(gè)代理對(duì)象飘诗,實(shí)際調(diào)用的時(shí)候与倡,實(shí)際上是調(diào)用的代理對(duì)象。 代理對(duì)象的實(shí)現(xiàn)了AOP的增強(qiáng)昆稿,實(shí)現(xiàn)了事物的實(shí)現(xiàn)纺座。

file

通過注解怎么實(shí)現(xiàn)指定的傳播特性和隔離級(jí)別的?

public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    String timeoutString() default "";

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

代碼中可以看出溉潭,我們可以指定隔離級(jí)別和傳播特性净响,在Spring為我們生成代理類的時(shí)候,會(huì)讀取這些屬性喳瓣,體現(xiàn)在增強(qiáng)邏輯中馋贤。

事物失效的8種情況及解決辦法

數(shù)據(jù)庫引擎不支持事務(wù)

這里以 MySQL 為例,其 MyISAM 引擎是不支持事務(wù)操作的畏陕,InnoDB 才是支持事務(wù)的引擎配乓,一般要支持事務(wù)都會(huì)使用 InnoDB,這時(shí)候選擇支持事物的數(shù)據(jù)庫即可(好像是廢話,哈哈哈)

沒有被 Spring 管理

這個(gè)好像沒什么可說的扰付,脫離了Spring的管理堤撵,還談什么Spring事物管理。

方法不是 public 的

@Transactional 只能用于 public 的方法上羽莺,否則事務(wù)不會(huì)失效实昨,如果要用在非 public 方法上,可以開啟 AspectJ 代理模式盐固。

數(shù)據(jù)源沒有配置事務(wù)管理器

相當(dāng)于沒開啟事務(wù)管理荒给,如果不是Springboot情況需要進(jìn)行如下操作。

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

如果是SpringBoot刁卜,在啟動(dòng)類上直接加上注解@EnableTransactionManagement即可志电。

傳播特性配錯(cuò)了

傳播特性配置成,Propagation.NOT_SUPPORTED或者Propagation.NOT_SUPPORTED蛔趴,改成支持事物的傳播特性即可挑辆。

異常類型錯(cuò)誤

因?yàn)槟J(rèn)的異常類型是運(yùn)行時(shí)異常,如果拋出了其他異常就不生效孝情。
解決方式:
1鱼蝉、將異常改成運(yùn)行時(shí)異常
2、指定異常進(jìn)行事物回滾箫荡,如:@Transactional(rollbackFor = Exception.class)

異常被吃掉了

如果你代碼這么寫,事物不生效:

    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {
       try {
        int r1 = userInfoDAO.updateUserName(1,"3");
        int r2 = userInfoDAO.updateUserName(2,"4");
        if (r2==1){
            throw new RuntimeException();
        }
        
            
        }catch (Exception e){
            
        }
    }

解決辦法: 必須要拋出異常魁亦,否則Spring事務(wù)管理,不會(huì)走到回滾邏輯

類內(nèi)部調(diào)用

@Service
public class UserInfoService {
    public void justUpdate(){
        updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {

    }
}

上述代碼不生效羔挡,因?yàn)閮?nèi)部調(diào)用不會(huì)涉及到代理類的調(diào)用洁奈,更不會(huì)有AOP的增強(qiáng),因此不會(huì)生效绞灼。
解決辦法:
1利术、自注入

@Service
public class UserInfoService {
   @Autowired
    private UserInfoService userInfoService;
    public void justUpdate(){
        userInfoService.updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {

    }
}

2、Spring上下文

@Service
public class UserInfoService {
    ApplicationContext applicationContext;
    public void justUpdate(){
           UserInfoService userInfoService = (UserInfoService) applicationContext.getBean("userInfoService");
        userInfoService.updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {
    }
}

3低矮、獲取他的代理類氯哮,直接調(diào)用代理類

@Service
public class UserInfoService {
    public void justUpdate(){
           ((UserInfoService) AopContext.currentProxy()).updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {
    }
}

----------------------------END---------------------------
更多Spring相關(guān)知識(shí),請(qǐng)關(guān)注我商佛,各平臺(tái)都是同一個(gè)ID

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末喉钢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子良姆,更是在濱河造成了極大的恐慌肠虽,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玛追,死亡現(xiàn)場(chǎng)離奇詭異税课,居然都是意外死亡闲延,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門韩玩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垒玲,“玉大人,你說我怎么就攤上這事找颓『嫌” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵击狮,是天一觀的道長佛析。 經(jīng)常有香客問我,道長彪蓬,這世上最難降的妖魔是什么寸莫? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮档冬,結(jié)果婚禮上膘茎,老公的妹妹穿的比我還像新娘。我一直安慰自己酷誓,他們只是感情好辽狈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呛牲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪驮配。 梳的紋絲不亂的頭發(fā)上娘扩,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音壮锻,去河邊找鬼琐旁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛猜绣,可吹牛的內(nèi)容都是我干的灰殴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼掰邢,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牺陶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辣之,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤掰伸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后怀估,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狮鸭,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡合搅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年居扒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惫谤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹋宦,死狀恐怖惯退,靈堂內(nèi)的尸體忽然破棺而出赌髓,到底是詐尸還是另有隱情,我是刑警寧澤蒸痹,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布春弥,位于F島的核電站,受9級(jí)特大地震影響叠荠,放射性物質(zhì)發(fā)生泄漏匿沛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一榛鼎、第九天 我趴在偏房一處隱蔽的房頂上張望逃呼。 院中可真熱鬧,春花似錦者娱、人聲如沸抡笼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽推姻。三九已至,卻和暖如春框沟,著一層夾襖步出監(jiān)牢的瞬間藏古,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工忍燥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拧晕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓梅垄,卻偏偏與公主長得像厂捞,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子队丝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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

  • 管理兩種方式 spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式靡馁。 編程式事務(wù)管理使用TransactionT...
    學(xué)編程的小屁孩閱讀 691評(píng)論 1 0
  • 1.概述 Spring 中的事務(wù)主要是利用 Aop 思想,簡(jiǎn)化事務(wù)的配置 2.核心接口 Spring事務(wù)管理的實(shí)現(xiàn)...
    Tian_Peng閱讀 580評(píng)論 0 1
  • Spring事務(wù)管理(詳解+實(shí)例)Spring詳解(八)------事務(wù)管理 一. 概念 事務(wù)(Transacti...
    WinkTink閱讀 341評(píng)論 0 0
  • 事務(wù)管理對(duì)于企業(yè)應(yīng)用而言至關(guān)重要机久。它保證了用戶的每一次操作都是可靠的奈嘿,即便出現(xiàn)了異常的訪問情況,也不至于破壞后臺(tái)數(shù)...
    桴海閱讀 262評(píng)論 0 0
  • 1 初步理解 理解事務(wù)之前吞加,先講一個(gè)你日常生活中最常干的事:取錢裙犹。比如你去ATM機(jī)取1000塊錢尽狠,大體有兩個(gè)步驟:...
    雷爺_fefc閱讀 365評(píng)論 0 1