最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳細談談Spring事務是如何管理的

 更新時間:2021年09月03日 11:55:55   作者:程序員阿牛  
在使用傳統(tǒng)的事務編程策略時,程序代碼必然和具體的事務操作代碼耦合,而使用Spring事務管理策略恰好可以避免這種尷尬,Spring的事務管理提供了兩種方式:編程式事務管理和聲明式事務管理,這篇文章主要給大家介紹了關于Spring事務是如何管理的相關資料,需要的朋友可以參考下

前言

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

Spring事務抽象

PlatformTransactionManager是事務管理器接口

//事務管理器接口有以下幾個接口,獲取事務信息,提交和回滾
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
    這些管理器都實現(xiàn)了PlatformTransactionManager中的三個接口,實現(xiàn)邏輯略有差別,但是對用戶來講區(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;
		//默認隔離級別,和數(shù)據(jù)庫的隔離級別一致
    int ISOLATION_DEFAULT = -1;
    int ISOLATION_READ_UNCOMMITTED = 1;
    int ISOLATION_READ_COMMITTED = 2;
    int ISOLATION_REPEATABLE_READ = 4;
    int ISOLATION_SERIALIZABLE = 8;
		//默認不超時
    int TIMEOUT_DEFAULT = -1;
}

下面兩張圖對這些參數(shù)進行了說明:

7種事務傳播特性:

四種事務隔離級別:

在看事務隔離級別前需要先了解下什么是臟讀、不可重復讀、幻讀

臟讀: 臟讀就是一個事物未提交的數(shù)據(jù),被另外一個事務讀到了,顯然這種情況不可接受

不可重復讀: 不可重復讀是指在一個事務內,多次讀同一數(shù)據(jù),前后讀取的結果不一致。

幻讀: 事務A對表中的一個數(shù)據(jù)進行了修改,這種修改涉及到表中的全部數(shù)據(jù)行。同時事務B也修改了這個表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么就會發(fā)生操作事務A的用戶發(fā)現(xiàn)表中還存在沒有修改的數(shù)據(jù)行,就好像發(fā)生了幻覺一樣

知道了以上幾個概念,我們來看看隔離級別:

這里我們可以看到,Spring并不是提供了所有的事務管理的實現(xiàn),而是提供了標準的事務管理器的操作接口PlatformTransactionManager, 并且規(guī)范了其行為,具體的事務實現(xiàn)由各個平臺自行實現(xiàn)。這就是Spring的事務抽象。

Spring之編程式事務

Spring提供了TransactionTemplate工具類可以很方便的使用編程式事務。默認情況下TransactionTemplate使用的是DataSourceTransactionManager。

在Spring上下文中,我們不配置TransactionTemplate這個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默認的事務傳播特性是PROPAGATION_REQUIRED,我們來做一下驗證,看是不是這樣

上面兩幅圖可以看出,TransactionStatus中的newTransaction屬性,第一個是true,第二個是false,正好符合PROPAGATION_REQUIRED所描述的情況。其他的傳播特性可以自己去驗證。

聲明式事務

除了編程式事務外,Spring還為我們提供了聲明式事務。使用@Transactional注解。

@Transactional 可以作用于接口、接口方法、類以及類方法上。當作用于類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該注解來覆蓋類級別的定義。

雖然 @Transactional 注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因為這只有在使用基于接口的代理時它才會生效。另外, @Transactional 注解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者默認可見性的方法上使用 @Transactional 注解,這將被忽略,也不會拋出任何異常。

@Transactional的rollbackFor屬性可以設置一個 Throwable 的數(shù)組,用來表明如果方法拋出這些異常,則進行事務回滾。默認情況下如果不配置rollbackFor屬性,那么事務只會在遇到RuntimeException的時候才會回滾。

下面的代碼事務就不會生效:

    @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,這時候事務就會生效了。或者指定異常讓事務生效,比如 @Transactional(rollbackFor = Exception.class),這樣碰到所有的異常事務都會生效了。

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

這是因為Spring容器會為加了這個注解的對象生成一個代理對象,實際調用的時候,實際上是調用的代理對象。 代理對象的實現(xiàn)了AOP的增強,實現(xiàn)了事務的實現(xiàn)。

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

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 {};
}

代碼中可以看出,我們可以指定隔離級別和傳播特性,在Spring為我們生成代理類的時候,會讀取這些屬性,體現(xiàn)在增強邏輯中。

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

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

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

沒有被 Spring 管理

這個好像沒什么可說的,脫離了Spring的管理,還談什么Spring事務管理。

方法不是 public 的

@Transactional 只能用于 public 的方法上,否則事務不會失效,如果要用在非 public 方法上,可以開啟 AspectJ 代理模式。

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

相當于沒開啟事務管理,如果不是Springboot情況需要進行如下操作。

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

如果是SpringBoot,在啟動類上直接加上注解@EnableTransactionManagement即可。

傳播特性配錯了

傳播特性配置成,Propagation.SUPPORTED或者Propagation.NOT_SUPPORTED,改成支持事務的傳播特性即可。

異常類型錯誤

因為默認的異常類型是運行時異常,如果拋出了其他異常就不生效。

解決方式:

1、將異常改成運行時異常

2、指定異常進行事務回滾,如:@Transactional(rollbackFor = Exception.class)

異常被吃掉了

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

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

解決辦法: 必須要拋出異常,否則Spring事務管理,不會走到回滾邏輯

類內部調用

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

    }
}

上述代碼不生效,因為內部調用不會涉及到代理類的調用,更不會有AOP的增強,因此不會生效。

解決辦法:

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、獲取他的代理類,直接調用代理類

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

總結

到此這篇關于Spring事務是如何管理的的文章就介紹到這了,更多相關Spring事務管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Mybatis?mysql模糊查詢方式(CONCAT多個字段)及bug

    Mybatis?mysql模糊查詢方式(CONCAT多個字段)及bug

    這篇文章主要介紹了Mybatis?mysql模糊查詢方式(CONCAT多個字段)及bug,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java使用Validation進行數(shù)據(jù)校驗的方式總結

    java使用Validation進行數(shù)據(jù)校驗的方式總結

    在Java中提供了一系列的校驗方式,下面這篇文章主要給大家介紹了關于java使用Validation進行數(shù)據(jù)校驗的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-06-06
  • 重試框架Guava-Retry和spring-Retry的使用示例

    重試框架Guava-Retry和spring-Retry的使用示例

    spring-retry 和 guava-retry 工具都是線程安全的重試,能夠支持并發(fā)業(yè)務場景的重試邏輯正確性,本文主要介紹了重試框架Guava-Retry和spring-Retry的使用示例,感興趣的可以一下
    2023-09-09
  • Idea安裝及涉及springboot詳細配置的圖文教程

    Idea安裝及涉及springboot詳細配置的圖文教程

    這篇文章主要介紹了Idea安裝及涉及springboot詳細配置,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10
  • 深入理解Java虛擬機 JVM 內存結構

    深入理解Java虛擬機 JVM 內存結構

    本節(jié)將會介紹一下JVM的內存結構,JVM運行時數(shù)據(jù)區(qū)的各個組成部分:堆,方法區(qū),程序計數(shù)器,Java虛擬機棧,本地方法棧,還會對Java堆的分代劃分做個簡單的介紹
    2021-09-09
  • 使用Servlet處理一個上傳的文件

    使用Servlet處理一個上傳的文件

    今天小編就為大家分享一篇關于使用Servlet處理一個上傳的文件,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Java StringBuffer與StringBuilder有什么區(qū)別

    Java StringBuffer與StringBuilder有什么區(qū)別

    當對字符串進行修改的時候,需要使用 StringBuffer 和 StringBuilder類,和String類不同的是,StringBuffer和 StringBuilder類的對象能夠被多次的修改,并且不產(chǎn)生新的未使用對象,本篇我們來分析分析它們的區(qū)別
    2023-01-01
  • Java多線程之死鎖的出現(xiàn)和解決方法

    Java多線程之死鎖的出現(xiàn)和解決方法

    本篇文章主要介紹了Java多線程之死鎖的出現(xiàn)和解決方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Spring Boot 集成Mybatis實現(xiàn)主從(多數(shù)據(jù)源)分離方案示例

    Spring Boot 集成Mybatis實現(xiàn)主從(多數(shù)據(jù)源)分離方案示例

    本篇文章主要介紹了Spring Boot 集成Mybatis實現(xiàn)主從(多數(shù)據(jù)源)分離方案實例,具有一定的參考價值,有興趣的可以了解一下。
    2017-03-03
  • java ArrayList按照同一屬性進行分組

    java ArrayList按照同一屬性進行分組

    這篇文章主要介紹了java ArrayList按照同一屬性進行分組的相關資料,需要的朋友可以參考下
    2017-02-02

最新評論

茌平县| 施甸县| 类乌齐县| 邛崃市| 晋宁县| 仲巴县| 大名县| 湟源县| 博乐市| 阿合奇县| 临西县| 三穗县| 清水县| 隆昌县| 石首市| 承德市| 麻城市| 房产| 阳新县| 怀柔区| 襄樊市| 家居| 大足县| 睢宁县| 宾阳县| 南丰县| 长白| 平阳县| 海林市| 婺源县| 红河县| 砀山县| 湖北省| 克什克腾旗| 彭山县| 武川县| 衢州市| 徐汇区| 遂昌县| 长岛县| 海盐县|