Spring事務(wù)詳解

image.png

前言

事務(wù)作用:在數(shù)據(jù)層保障一系列的數(shù)據(jù)庫操作同成功同失敗。
Spring事務(wù)作用:在數(shù)據(jù)層或業(yè)務(wù)層保障一系列的數(shù)據(jù)庫操作同成功同失敗。

Spring事務(wù)

關(guān)于事務(wù)的使用通過在案例中來講解比較直觀全面。
本文以案例的方式來詳解Spring事務(wù)。

案例:模擬銀行賬戶之間的轉(zhuǎn)賬業(yè)務(wù)。
需求:實(shí)現(xiàn)兩個賬戶(A,B)之間的轉(zhuǎn)賬操作。

業(yè)務(wù)分析:

  1. 數(shù)據(jù)層提供基礎(chǔ)操作,指定賬戶減錢(outMoney),指定賬戶加錢(inMoney)。
  2. 業(yè)務(wù)層提供轉(zhuǎn)賬操作(transfer),調(diào)動減錢與加錢的操作。
  3. 提供2個賬號和操作金額執(zhí)行轉(zhuǎn)賬操作。
  4. 基于Spring整合MyBatis環(huán)境搭建上述操作。

結(jié)果分析:

  1. 程序正常執(zhí)行時,賬戶金額A減B加,沒有問題。
  2. 程序出現(xiàn)異常后,轉(zhuǎn)賬失敗,但是異常之前操作成功,異常之后操作失敗,整體業(yè)務(wù)失敗。

1. 快速實(shí)現(xiàn)

1.1 在業(yè)務(wù)層接口上添加Spring事務(wù)管理

public interface AccountService {
    @Transactional
    void transfer(String out, String in, Double money);
}

注意:
Spring注解式事務(wù)通常添加在業(yè)務(wù)層接口中而不會添加到業(yè)務(wù)層實(shí)現(xiàn)類中,降低耦合。
注解式事務(wù)可以添加到業(yè)務(wù)方法上表示當(dāng)前方法開啟事務(wù),也可以添加到接口上表示當(dāng)前接口所有方法開啟事務(wù)。

1.2 設(shè)置事務(wù)管理器

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

注意:
事務(wù)管理器要根據(jù)實(shí)現(xiàn)技術(shù)進(jìn)行選擇
MyBatis框架使用的是JDBC事務(wù)

1.3 開啟注解式事務(wù)驅(qū)動

Spring配置類中使用注解@EnableTransactionManagement開啟事務(wù)驅(qū)動

@Configuration
@ComponentScan({"com.hao.service", "com.hao.dao", "com.hao.aop"})
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class, MyBatisConfig.class})
@EnableTransactionManagement
public class SpringConfig {
}

2. Spring事務(wù)角色

2.1 事務(wù)管理員

發(fā)起事務(wù)方,在Spring中通常指代業(yè)務(wù)層開啟事務(wù)的方法。

如這里AccountService中的transfer方法是事務(wù)管理員。該方法執(zhí)行時會開啟一個事務(wù)。

@Transactional
public void transfer(String out, String in, Double money) {
    accountDao.outMoney(out, money);
    accountDao.inMoney(in, money);
}

2.1 事務(wù)協(xié)調(diào)員

加入事務(wù)方,在Spring中通常指代數(shù)據(jù)層方法,也可以是業(yè)務(wù)層方法 。

由于AccountDaoAccountService中的transfer方法中被調(diào)用,而且transfer開啟了事務(wù),所以這里AccountDao中的inMoneyoutMoney方法都是事務(wù)協(xié)調(diào)員。這兩個方法也會開啟相應(yīng)的事務(wù)并加入事務(wù)管理員的事務(wù),這樣來保證整體業(yè)務(wù)的同成功同失敗。

public interface AccountDao {
    @Update("update tb_account set money = money + #{money} where name = #{name}")
    void inMoney(@Param("name") String name, @Param("money") Double money);
    
    @Update("update tb_account set money = money - #{money} where name = #{name}")
    void outMoney(@Param("name") String name, @Param("money") Double money);
}

3. 事務(wù)相關(guān)配置

@Transactional注解中的屬性及作用如下圖:

image.png

這里主要是屬性rollbackFor會常用到,因?yàn)?code>Spring事務(wù)并不是對于所有異常都會回滾,通過這個屬性可以設(shè)置必須回滾的異常。比如可以進(jìn)行如下設(shè)置:

public interface AccountService {
    @Transactional(rollbackFor = {IOException.class, NullPointerException.class})
    void transfer(String out, String in, Double money);
}

4. 事務(wù)傳播行為

上邊我們通過事務(wù)回滾達(dá)到了業(yè)務(wù)同成功同失敗的需求。但是開發(fā)中可能也會遇到不需要事務(wù)管理員中的所有協(xié)調(diào)員都進(jìn)行回滾。
比如在transfer中增加一個日志打印的業(yè)務(wù),要求無論transfer是否執(zhí)行成功,都進(jìn)行日志打印。

public interface LogService {
    void log(String out, String in, Double money);
}
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;
    @Autowired
    private LogService logService;

    @Override
    public void transfer(String out, String in, Double money) {
        try {
            accountDao.outMoney(out, money);
            int i = 10 / 0;
            accountDao.inMoney(in, money);
        } finally {
            logService.log(out, in, money);
        }
    }
}

這么寫看起來沒什么問題,但是當(dāng)出現(xiàn)異常進(jìn)行回滾時,LogService也會進(jìn)行回滾,這樣就無法記錄當(dāng)次操作。

這就要用到事務(wù)傳播行為,即事務(wù)協(xié)調(diào)員對事務(wù)管理員所攜帶事務(wù)的處理態(tài)度。

需要在LogServicelog方法上增加事務(wù)注解并設(shè)置propagation = Propagation.REQUIRES_NEW,如下:

@Service
public class LogServiceImpl implements LogService {
    @Autowired
    private LogDao logDao;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void log(String out, String in, Double money) {
        logDao.log("轉(zhuǎn)賬操作由" + out + "到" + in + ",金額:" + money);
    }
}

該設(shè)置意思是LogServicelog方法會開啟新的事務(wù),不加入事務(wù)管理員。這樣無論事務(wù)管理員的事務(wù)如何回滾,都不會影響LogServicelog方法的執(zhí)行。

關(guān)于事務(wù)傳播行為屬性有如下類型:

image.png

可以根據(jù)需求進(jìn)行相應(yīng)的設(shè)置。

總結(jié)

以上就是關(guān)于Spring事務(wù)的全部內(nèi)容。

如果有什么問題,我們可以一起交流討論解決。

最后,希望可以幫助到有需要的碼友。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 事務(wù)特性(ACID) 原子性: 事務(wù)是最小的執(zhí)行單位,不允許分割。事務(wù)的原子性確保動作要么全部完成,要么完全不起作...
    Q南南南Q閱讀 402評論 0 0
  • 事務(wù)接口定義 在Spring中,事務(wù)是通過TransactionDefinition接口定義的。其中定義了訪問事務(wù)...
    追夢人Plus閱讀 1,171評論 0 12
  • 數(shù)據(jù)庫事務(wù)原理詳解 1.事務(wù)的基本概念 ??事務(wù)(Transaction)是訪問并可能更新數(shù)據(jù)庫中各種數(shù)據(jù)項(xiàng)的一個...
    沈先生的影子閱讀 796評論 0 1
  • 1 初步理解 理解事務(wù)之前,先講一個你日常生活中最常干的事:取錢。 比如你去ATM機(jī)取1000塊錢,大體有兩個步驟...
    陳陳陳老師呀閱讀 317評論 0 0
  • 1. 關(guān)于事務(wù) 事務(wù)控制就是將一系列操作當(dāng)成一個不可拆分的邏輯單元,保證這些操作要么都成功,要么都失敗。在關(guān)系數(shù)據(jù)...
    七弦桐語閱讀 2,912評論 0 14