久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Spring Boot 中使用 @Transactional 注解配置事務(wù)管理

 印度阿三17 2019-08-14
轉(zhuǎn)載自:https://blog.csdn.net/nextyu/article/details/78669997,,作者:皂白

事務(wù)管理是應(yīng)用系統(tǒng)開(kāi)發(fā)中必不可少的一部分。Spring 為事務(wù)管理提供了豐富的功能支持,。Spring 事務(wù)管理分為編程式和聲明式的兩種方式,。編程式事務(wù)指的是通過(guò)編碼方式實(shí)現(xiàn)事務(wù);聲明式事務(wù)基于 AOP,將具體業(yè)務(wù)邏輯與事務(wù)處理解耦,。聲明式事務(wù)管理使業(yè)務(wù)代碼邏輯不受污染, 因此在實(shí)際使用中聲明式事務(wù)用的比較多,。聲明式事務(wù)有兩種方式,一種是在配置文件(xml)中做相關(guān)的事務(wù)規(guī)則聲明,,另一種是基于?@Transactional?注解的方式,。本文將著重介紹基于?@Transactional?注解的事務(wù)管理。

需要明確幾點(diǎn):

  1. 默認(rèn)配置下?Spring 只會(huì)回滾運(yùn)行時(shí),、未檢查異常(繼承自 RuntimeException 的異常)或者 Error,。參考這里
  2. @Transactional?注解只能應(yīng)用到 public 方法才有效。參考這里 Method visibility and @Transactional

以下的示例使用的是 mybatis,,所以 spring boot 會(huì)自動(dòng)配置一個(gè)?DataSourceTransactionManager,,我們只需在方法(或者類)加上?@Transactional?注解,就自動(dòng)納入 Spring 的事務(wù)管理了,。

簡(jiǎn)單的使用方法

只需在方法加上?@Transactional?注解就可以了,。

如下有一個(gè)保存用戶的方法,,加入?@Transactional?注解,使用默認(rèn)配置,,拋出異常之后,,事務(wù)會(huì)自動(dòng)回滾,數(shù)據(jù)不會(huì)插入到數(shù)據(jù)庫(kù),。

@Transactional
@Override
public void save() {
    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 拋異常了");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

我們可以從日志里面看出這些信息

TIM截圖20171129135813

@Transactional 注解的屬性介紹

下面分別介紹一下?@Transactional?的幾個(gè)屬性,。

value 和 transactionManager 屬性

它們兩個(gè)是一樣的意思。當(dāng)配置了多個(gè)事務(wù)管理器時(shí),,可以使用該屬性指定選擇哪個(gè)事務(wù)管理器,。

propagation 屬性

事務(wù)的傳播行為,默認(rèn)值為 Propagation.REQUIRED,。

可選的值有:

  • Propagation.REQUIRED

    如果當(dāng)前存在事務(wù),,則加入該事務(wù),如果當(dāng)前不存在事務(wù),,則創(chuàng)建一個(gè)新的事務(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)建一個(gè)新的事務(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

    和 Propagation.REQUIRED 效果一樣,。

這些概念理解起來(lái)實(shí)在是有點(diǎn)兒抽象,后文會(huì)用代碼示例解釋說(shuō)明,。

isolation 屬性

事務(wù)的隔離級(jí)別,,默認(rèn)值為 Isolation.DEFAULT。

可選的值有:

  • Isolation.DEFAULT

    使用底層數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別。

  • Isolation.READ_UNCOMMITTED

  • Isolation.READ_COMMITTED
  • Isolation.REPEATABLE_READ
  • Isolation.SERIALIZABLE

timeout 屬性

事務(wù)的超時(shí)時(shí)間,,默認(rèn)值為-1,。如果超過(guò)該時(shí)間限制但事務(wù)還沒(méi)有完成,則自動(dòng)回滾事務(wù),。

readOnly 屬性

指定事務(wù)是否為只讀事務(wù),,默認(rèn)值為 false;為了忽略那些不需要事務(wù)的方法,,比如讀取數(shù)據(jù),,可以設(shè)置 read-only 為 true。

rollbackFor 屬性

用于指定能夠觸發(fā)事務(wù)回滾的異常類型,,可以指定多個(gè)異常類型,。

noRollbackFor 屬性

拋出指定的異常類型,不回滾事務(wù),,也可以指定多個(gè)異常類型,。

@Transactional 的 propagation 屬性代碼示例

比如如下代碼,save 方法首先調(diào)用了 method1 方法,,然后拋出了異常,,就會(huì)導(dǎo)致事務(wù)回滾,如下兩條數(shù)據(jù)都不會(huì)插入數(shù)據(jù)庫(kù),。

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 拋異常了");
    }
}

public void method1() {
    User user = new User("宮本武藏");
    userMapper.insertSelective(user);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

現(xiàn)在有需求如下,,就算 save 方法的后面拋異常了,也不能影響 method1 方法的數(shù)據(jù)插入,?;蛟S很多人的想法如下,給 method1 頁(yè)加入一個(gè)新的事務(wù),,這樣 method1 就會(huì)在這個(gè)新的事務(wù)中執(zhí)行,,原來(lái)的事務(wù)不會(huì)影響到新的事務(wù)。比如 method1 方法上面再加入注解 @Transactional,,設(shè)置 propagation 屬性為 Propagation.REQUIRES_NEW,代碼如下,。

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 拋異常了");
    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1() {
    User user = new User("宮本武藏");
    userMapper.insertSelective(user);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

運(yùn)行之后,,發(fā)現(xiàn)然并卵,數(shù)據(jù)也是沒(méi)有插入數(shù)據(jù)庫(kù),。怎么肥四,,看起來(lái)很不科學(xué)。我們先來(lái)看看日志內(nèi)容,。

TIM截圖20171129150737

從日志內(nèi)容可以看出,,其實(shí)兩個(gè)方法都是處于同一個(gè)事務(wù)中,method1 方法并沒(méi)有創(chuàng)建一個(gè)新的事務(wù)。

這就得看看?Spring 官方文檔了,。

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.

大概意思:在默認(rèn)的代理模式下,,只有目標(biāo)方法由外部調(diào)用,才能被 Spring 的事務(wù)攔截器攔截,。在同一個(gè)類中的兩個(gè)方法直接調(diào)用,,是不會(huì)被 Spring 的事務(wù)攔截器攔截,就像上面的 save 方法直接調(diào)用了同一個(gè)類中的 method1方法,,method1 方法不會(huì)被 Spring 的事務(wù)攔截器攔截,。可以使用 AspectJ 取代 Spring AOP 代理來(lái)解決這個(gè)問(wèn)題,,但是這里暫不討論,。

為了解決這個(gè)問(wèn)題,我們可以新建一個(gè)類,。

@Service
public class OtherServiceImpl implements OtherService {

    @Autowired
    private UserMapper userMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void method1() {
        User user = new User("風(fēng)魔小太郎");
        userMapper.insertSelective(user);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

然后在 save 方法中調(diào)用 otherService.method1 方法

@Autowired
private OtherService otherService;

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    otherService.method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 拋異常了");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

這下,,otherService.method1 方法的數(shù)據(jù)插入成功,save 方法的數(shù)據(jù)未插入,,事務(wù)回滾,。

繼續(xù)看一下日志內(nèi)容

TIM截圖20171129153731

從日志可以看出,首先創(chuàng)建了 save 方法的事務(wù),,由于 otherService.method1 方法的 @Transactional 的 propagation 屬性為 Propagation.REQUIRES_NEW ,,所以接著暫停了 save 方法的事務(wù),重新創(chuàng)建了 otherService.method1 方法的事務(wù),,接著 otherService.method1 方法的事務(wù)提交,,接著 save 方法的事務(wù)回滾。這就印證了只有目標(biāo)方法由外部調(diào)用,,才能被 Spring 的事務(wù)攔截器攔截,。

還有幾個(gè)示例如下。

接著把 save 方法的 @Transactional 注解去掉,,otherService.method1 的 @Transactional 注解保持不變,,從日志就可以看出,只會(huì)創(chuàng)建一個(gè) otherService.method1 方法的事務(wù),,兩條數(shù)據(jù)都會(huì)插入,。

@Autowired
private OtherService otherService;

//    @Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    otherService.method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 拋異常了");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

接著把 save 方法的 @Transactional 注解去掉,save 方法改為調(diào)用內(nèi)部的 method1 方法,,從日志就可以看出,,完全沒(méi)有創(chuàng)建任何事務(wù),兩條數(shù)據(jù)都會(huì)插入,。

//    @Transactional(propagation = Propagation.REQUIRED)
@Override
public void save() {

    method1();

    User user = new User("服部半藏");
    userMapper.insertSelective(user);

    if (true) {
        throw new RuntimeException("save 拋異常了");
    }
}


@Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1() {
    User user = new User("宮本武藏");
    userMapper.insertSelective(user);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

這樣,,其他的幾個(gè) propagation 屬性值也就比較好理解了,。

@Transactional 事務(wù)實(shí)現(xiàn)機(jī)制

在應(yīng)用系統(tǒng)調(diào)用聲明了?@Transactional?的目標(biāo)方法時(shí),Spring Framework 默認(rèn)使用 AOP 代理,,在代碼運(yùn)行時(shí)生成一個(gè)代理對(duì)象,,根據(jù)?@Transactional?的屬性配置信息,這個(gè)代理對(duì)象決定該聲明?@Transactional?的目標(biāo)方法是否由攔截器?TransactionInterceptor?來(lái)使用攔截,,在?TransactionInterceptor?攔截時(shí),,會(huì)在目標(biāo)方法開(kāi)始執(zhí)行之前創(chuàng)建并加入事務(wù),并執(zhí)行目標(biāo)方法的邏輯, 最后根據(jù)執(zhí)行情況是否出現(xiàn)異常,,利用抽象事務(wù)管理器?AbstractPlatformTransactionManager?操作數(shù)據(jù)源?DataSource?提交或回滾事務(wù),。

Spring AOP 代理有?CglibAopProxy?和?JdkDynamicAopProxy?兩種,以?CglibAopProxy?為例,,對(duì)于?CglibAopProxy,,需要調(diào)用其內(nèi)部類的?DynamicAdvisedInterceptor?的 intercept 方法。對(duì)于?JdkDynamicAopProxy,,需要調(diào)用其 invoke 方法,。

Spring-transaction-mechanis

正如上文提到的,事務(wù)管理的框架是由抽象事務(wù)管理器?AbstractPlatformTransactionManager?來(lái)提供的,,而具體的底層事務(wù)處理實(shí)現(xiàn),,由?PlatformTransactionManager?的具體實(shí)現(xiàn)類來(lái)實(shí)現(xiàn),如事務(wù)管理器?DataSourceTransactionManager,。不同的事務(wù)管理器管理不同的數(shù)據(jù)資源?DataSource,,比如?DataSourceTransactionManager?管理 JDBC 的?Connection

Spring-TransactionManager-hierarchy-subtypes

源碼地址

參考資料

來(lái)源:https://www./content-4-390351.html

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多