自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇文章徹底吃透 Spring 的事務(wù)實(shí)現(xiàn)

開發(fā) 前端
編程式的事務(wù)管理比較靈活,如果當(dāng)前操作非常耗時(shí),可以采用編程式的事務(wù)管理來(lái)提交事務(wù),避免長(zhǎng)事務(wù)影響數(shù)據(jù)庫(kù)性能;其次如果數(shù)據(jù)操作比較簡(jiǎn)單時(shí)間短,可以采用聲明式事務(wù)管理,如果使用不當(dāng),可能會(huì)導(dǎo)致事務(wù)失效,因此在實(shí)際使用中要多加小心。

一、背景介紹

今天我們接著來(lái)聊聊 SpringBoot 事務(wù)相關(guān)的具體使用方式。

何謂事務(wù)?熟悉數(shù)據(jù)庫(kù)的同學(xué)可能比較熟悉,對(duì)于任意一組 SQL 語(yǔ)句,要么全部執(zhí)行成功,要么全部執(zhí)行失??;如果中途因?yàn)槟硞€(gè)原因其中一條語(yǔ)句執(zhí)行失敗,那么先前執(zhí)行過(guò)的語(yǔ)句將全部撤回。

事務(wù)控制的好處在于:可以保證數(shù)據(jù)操作的安全性。比如,當(dāng)你給某個(gè)客戶 A 轉(zhuǎn)賬 100 塊,此時(shí)銀行需要從你的個(gè)人賬戶中扣除 100 塊,然后再給客戶 A 賬戶增加 100 塊,這其實(shí)是兩個(gè)動(dòng)作,假如銀行在操作客戶 A 的賬戶時(shí)出現(xiàn)故障,此時(shí)你個(gè)人賬戶的錢已經(jīng)被扣除,但對(duì)方的賬戶并沒(méi)有到賬,這將會(huì)給客戶產(chǎn)生重大損失。有了事務(wù)控制之后,當(dāng)操作對(duì)方的賬戶發(fā)生異常時(shí),可以將個(gè)人賬戶中扣除的錢進(jìn)行撤回,從而保證用戶資金賬戶的安全性。

Java 作為一個(gè)高級(jí)開發(fā)語(yǔ)言,同樣支持?jǐn)?shù)據(jù)庫(kù)的事務(wù)控制。在上文中,我們了解到所有涉及到數(shù)據(jù)庫(kù)的操作,都需要通過(guò)數(shù)據(jù)庫(kù)連接對(duì)象來(lái)完成。當(dāng)我們?cè)诓僮鲾?shù)據(jù)庫(kù)時(shí),如果想要開啟手動(dòng)事務(wù)控制(默認(rèn)是自動(dòng)提交),其實(shí)通過(guò)連接對(duì)象的autoCommit參數(shù)就可以完成,例如如下示例:

// 1.加載數(shù)據(jù)庫(kù)驅(qū)動(dòng)包
Class.forName(DRIVER_CLASS);
// 2.創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接實(shí)例
Connection conn = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
Statement statement = null;
try {
    // 3.設(shè)置手動(dòng)事務(wù)提交,默認(rèn)是true
    conn.setAutoCommit(false);
    // 4.執(zhí)行多條SQL語(yǔ)句
    statement = conn.createStatement();
    statement.executeUpdate("insert into tb_user(id, name) values(1, 'tom') ");
    statement.executeUpdate("insert into tb_role(id, name) values(1, 'sys') ");
    ...
    // 5.提交事務(wù)
    conn.commit();
} catch (SQLException e) {
    // 如果SQL執(zhí)行異常,回滾事務(wù)
    conn.rollback();
}

// 6.關(guān)閉連接
statement.close();
conn.close();

了解了 JDBC 的事務(wù)控制之后,再來(lái)學(xué)習(xí) SpringBoot 事務(wù)控制就要容易的多,下面我們一起來(lái)看看相關(guān)的使用方式。

二、SpringBoot 事務(wù)

在 Spring 中事務(wù)有兩種實(shí)現(xiàn)方式,分別是編程式事務(wù)管理和聲明式事務(wù)管理。

  • 編程式事務(wù)管理:利用的是TransactionTemplate類或者更底層的PlatformTransactionManager事務(wù)管理器來(lái)控制事務(wù)操作,用戶可以手動(dòng)提交或者回滾事務(wù),編程上比較靈活
  • 聲明式事務(wù)管理:利用的是@Transactional注解對(duì)事務(wù)進(jìn)行管理,本質(zhì)是通過(guò) AOP 對(duì)方法前后進(jìn)行攔截,在目標(biāo)方法開始之前創(chuàng)建或者加入一個(gè)事務(wù),目標(biāo)方法執(zhí)行完成之后根據(jù)情況進(jìn)行提交或者回滾事務(wù),使用上比較簡(jiǎn)單,易上手

當(dāng)我們使用  SpringBoot 框架來(lái)開發(fā)項(xiàng)目的時(shí)候,SpringBoot 會(huì)自動(dòng)將 Spring 對(duì)數(shù)據(jù)庫(kù)事務(wù)支持的依賴庫(kù)加載到工程中,無(wú)需再次添加相關(guān)依賴包。

下面我們以之前介紹的 SpringBoot 整合 mybatis 的工程為例子,利用事務(wù)控制來(lái)執(zhí)行多表數(shù)據(jù)插入操作,一起來(lái)看看這兩種事務(wù)管理的應(yīng)用方式。

2.1、編程式事務(wù)管理

編程式事務(wù)管理主要有兩種實(shí)現(xiàn)方式,第一種是利用TransactionTemplate類來(lái)提交事務(wù),編程簡(jiǎn)單靈活,也是常用的方式之一;另一種是采用PlatformTransactionManager事務(wù)管理器來(lái)控制事務(wù)的提交和回滾。

我們先看看更底層的PlatformTransactionManager接口應(yīng)用方式。

2.1.1、PlatformTransactionManager 事務(wù)管理器

利用PlatformTransactionManager事務(wù)管理器來(lái)實(shí)現(xiàn)事務(wù)的操作,示例如下:

@Service
publicclass ApiService {

    privatestaticfinal Logger LOGGER = LoggerFactory.getLogger(ApiService.class);

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void insert(Role role, Menu menu){
        //手動(dòng)開啟事務(wù)
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        try {
            // 新增角色信息
            roleMapper.insert(role);
            // 新增菜單信息
            menuMapper.insert(menu);
            // 提交事務(wù)
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滾事務(wù)
            transactionManager.rollback(status);
            LOGGER.error("提交數(shù)據(jù)異常",e);
        }
    }
}

在執(zhí)行角色信息插入和菜單信息插入的時(shí)候,如果都成功,則提交事務(wù);如果任意其中一個(gè)方法失敗,整個(gè)操作進(jìn)行回滾。

關(guān)于事務(wù)管理器,無(wú)論采用的是 JPA 還是 JDBC 等,底層的事務(wù)管理器都實(shí)現(xiàn)自PlatformTransactionManager接口。如果采用的是spring-boot-starter-jdbc或者M(jìn)ybatis操作數(shù)據(jù)庫(kù),Spring Boot 框架會(huì)默認(rèn)將DataSourceTransactionManager實(shí)例作為實(shí)現(xiàn)類;如果采用的是spring-boot-starter-data-jpa,框架會(huì)默認(rèn)將JpaTransactionManager實(shí)例作為實(shí)現(xiàn)類。

關(guān)于這一點(diǎn),我們可以寫一個(gè)測(cè)試方法來(lái)查看PlatformTransactionManager接口的實(shí)現(xiàn)類,具體如下:

@MapperScan("com.example.mybatis.mapper")
@SpringBootApplication
publicclass Application {

    @Bean
    public Object testBean(PlatformTransactionManager platformTransactionManager){
        System.out.println("transactionManager:" + platformTransactionManager.getClass().getName());
        returnnew Object();
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

啟動(dòng)服務(wù),輸出結(jié)果如下:

transactionManager:org.springframework.jdbc.datasource.DataSourceTransactionManager

2.1.2、TransactionTemplate 事務(wù)模板類

除了采用事務(wù)管理器來(lái)實(shí)現(xiàn)事務(wù)手動(dòng)控制,Spring 事務(wù)框架還為用戶提供了TransactionTemplate事務(wù)模板類,通過(guò)它也可以實(shí)現(xiàn)事務(wù)的手動(dòng)控制,并且操作更加簡(jiǎn)單,示例如下:

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    /**
     * 方式一:帶返回值的事務(wù)提交
     * @param role
     * @param menu
     */
    public void insert1(Role role, Menu menu){
        Integer result =transactionTemplate.execute(status -> {
            // 新增角色信息
            roleMapper.insert(role);
            // 新增菜單信息
            menuMapper.insert(menu);
            return1;
        });
    }

    /**
     * 方式二:忽略返回值的事務(wù)提交
     * @param role
     * @param menu
     */
    public void insert2(Role role, Menu menu){
        transactionTemplate.execute(status -> {
            // 新增角色信息
            roleMapper.insert(role);
            // 新增菜單信息
            menuMapper.insert(menu);
            returnnull;
        });
    }

    /**
     * 方式三:不帶返回值的事務(wù)提交
     * @param role
     * @param menu
     */
    public void insert3(Role role, Menu menu){
        transactionTemplate.execute(new TransactionCallbackWithoutResult(){

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                // 新增角色信息
                roleMapper.insert(role);
                // 新增菜單信息
                menuMapper.insert(menu);
            }
        });
    }
}

以上三種方式,都可以實(shí)現(xiàn)實(shí)現(xiàn)事務(wù)的手動(dòng)控制,效果等同于采用事務(wù)管理器來(lái)實(shí)現(xiàn)事務(wù)手動(dòng)控制。

如果仔細(xì)翻查TransactionTemplate類的execute()方法,你會(huì)發(fā)現(xiàn)它底層的實(shí)現(xiàn)邏輯,與上文介紹的利用事務(wù)管理器來(lái)控制事務(wù)的提交和回滾操作類似。

execute()方法的部分核心源碼如下!

圖片圖片

因此,在編程式事務(wù)管理方式下,推薦采用TransactionTemplate類來(lái)實(shí)現(xiàn),編程上會(huì)更加靈活簡(jiǎn)單。

2.2、聲明式事務(wù)管理

聲明式事務(wù)管理就更加簡(jiǎn)單了,只需要在方法上增加注解@Transactional即可,無(wú)需任何配置。

2.2.1、Transactional 注解應(yīng)用示例

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Transactional
    public void insert(Role role, Menu menu){
        // 新增角色信息
        roleMapper.insert(role);
        // 新增菜單信息
        menuMapper.insert(menu);
    }
}

聲明式事務(wù)管理方式,本質(zhì)采用的是 AOP 動(dòng)態(tài)代理的方式,對(duì)標(biāo)注@Transactional注解的方法進(jìn)行前后攔截,然后通過(guò)事務(wù)管理器來(lái)實(shí)現(xiàn)事務(wù)控制。

盡管@Transactional注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 不推薦在接口或者接口方法上使用該注解,如果編程不當(dāng)某些場(chǎng)景下可能會(huì)失效。當(dāng)作用于類上,那么該類的所有public方法將都具有事務(wù)屬性。在實(shí)際使用過(guò)程中,推薦在類的方法上使用該注解,以便實(shí)現(xiàn)精準(zhǔn)的事務(wù)控制。

2.2.2、Transactional 注解失效場(chǎng)景

在使用@Transactional注解時(shí),有以下幾個(gè)場(chǎng)景,事務(wù)可能不會(huì)生效!

  • 場(chǎng)景一:@Transactional注解如果應(yīng)用在非public方法,事務(wù)不會(huì)生效,并且不會(huì)拋異常,該注解只會(huì)代理public修飾的方法
  • 場(chǎng)景二:同一個(gè)類中的方法,調(diào)用標(biāo)注@Transactional注解的方法,事務(wù)控制也不會(huì)生效
  • 場(chǎng)景三:內(nèi)部異常如果被catch吃了,事務(wù)不會(huì)回滾
  • 場(chǎng)景四:@Transactional注解默認(rèn)只對(duì)運(yùn)行時(shí)異常或者 Error 才回滾事務(wù),其它場(chǎng)景不會(huì)觸發(fā)事務(wù)回滾,如果異常不在范圍之內(nèi),事務(wù)不會(huì)回滾
  • 場(chǎng)景五:@Transactional注解上的配置參數(shù)使用不當(dāng),可能導(dǎo)致事務(wù)失效

下面我們每個(gè)場(chǎng)景下,錯(cuò)誤的用法。

事務(wù)失效:場(chǎng)景一

@Transactional注解應(yīng)該只被應(yīng)用到public方法上,如果應(yīng)用在非public方法,事務(wù)不會(huì)生效,并且不會(huì)拋異常,錯(cuò)誤示例如下:

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Transactional
    protected void insert(Role role, Menu menu){
        // 新增角色信息
        roleMapper.insert(role);
        // 新增菜單信息
        menuMapper.insert(menu);
    }
}

此時(shí),執(zhí)行insert操作的時(shí)候會(huì)自動(dòng)提交,Spring Boot 不會(huì)開啟事務(wù)控制。假如menuService.insert()方法執(zhí)行異常,此時(shí)roleService.insert()提交的數(shù)據(jù)不會(huì)回滾。

原因在于:@Transactional注解只會(huì)代理public修飾的方法,由 Spring AOP 代理決定的。

事務(wù)失效:場(chǎng)景二

同一個(gè)類中的方法,如果調(diào)用標(biāo)注@Transactional注解的方法,事務(wù)控制也不會(huì)生效,錯(cuò)誤示例如下:

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    public void save(Role role, Menu menu){
        insert(role, menu);
    }

    @Transactional
    public void insert(Role role, Menu menu){
        // 新增角色信息
        roleMapper.insert(role);
        // 新增菜單信息
        menuMapper.insert(menu);
    }
}

當(dāng)外部調(diào)用save()方法來(lái)保存數(shù)據(jù)的時(shí)候,此時(shí) Spring Boot 不會(huì)開啟事務(wù)控制,會(huì)自動(dòng)提交數(shù)據(jù),如果執(zhí)行過(guò)程中發(fā)生異常,之前執(zhí)行過(guò)的數(shù)據(jù)操作不會(huì)回滾。

原因在于:被@Transactional標(biāo)注的方法,只有被當(dāng)前類以外的代碼調(diào)用時(shí),才會(huì)由 Spring Aop 生成的代理對(duì)象來(lái)管理。

事務(wù)失效:場(chǎng)景三

被@Transactional標(biāo)注的方法,內(nèi)部異常如果被手動(dòng)catch吃了,事務(wù)不會(huì)回滾,錯(cuò)誤示例如下:

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Transactional
    public void insert(Role role, Menu menu){
        try {
            // 新增角色信息
            roleMapper.insert(role);
            // 新增菜單信息
            menuMapper.insert(menu);
        } catch (Exception e){
            e.printStackTrace();
            // todo..
        }
    }
}

此時(shí),被@Transactional標(biāo)注的方法具備事務(wù)控制,如果執(zhí)行過(guò)程中發(fā)生異常,數(shù)據(jù)不會(huì)回滾,因?yàn)楫惓1徊东@了。當(dāng) Spring AOP 事務(wù)代理類沒(méi)有感知到異常時(shí),會(huì)自動(dòng)提交事務(wù)。

事務(wù)失效:場(chǎng)景四

@Transactional注解默認(rèn)只對(duì)運(yùn)行時(shí)異常或者 Error 才回滾事務(wù),其它場(chǎng)景不會(huì)觸發(fā)事務(wù)回滾,如果異常不在范圍之內(nèi),事務(wù)不會(huì)回滾,錯(cuò)誤示例如下:

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Transactional
    public void insert(Role role, Menu menu) throws Exception {
        try {
            // 新增角色信息
            roleMapper.insert(role);
            // 新增菜單信息
            menuMapper.insert(menu);
        } catch (Exception e){
            thrownew Exception("保存錯(cuò)誤");
        }
    }
}

此時(shí)中途如果插入數(shù)據(jù)失敗,會(huì)拋Exception異常,但是之前執(zhí)行成功的數(shù)據(jù)不會(huì)回滾。

如果想要支持其它類型的異常,可以在@Transactional注解類上配置rollbackFor參數(shù),比如如下示例:

@Transactional(rollbackFor = Exception.class)

這個(gè)參數(shù)配置僅限于 Throwable 異常類及其子類。

事務(wù)失效:場(chǎng)景五

在@Transactional注解類上,其實(shí)隱含了很多的事務(wù)屬性參數(shù),如果參數(shù)配置不當(dāng),可能也會(huì)導(dǎo)致事務(wù)失效,錯(cuò)誤示例如下:

@Service
publicclass ApiService {

    @Autowired
    private RoleService roleService;

    @Autowired
    private MenuService menuService;

    @Transactional(readOnly = true)
    public void insert(Role role, Menu menu){
        // 新增角色信息
        roleService.insert(role);
        // 新增菜單信息
        menuService.insert(menu);
    }
}

此時(shí)提交數(shù)據(jù)會(huì)報(bào)錯(cuò),因?yàn)閞eadOnly = true參數(shù)表示只讀模式,不能對(duì)數(shù)據(jù)庫(kù)的數(shù)據(jù)進(jìn)行更改操作。

三、事務(wù)注解詳解

在上文中,我們介紹了@Transactional事務(wù)注解的基本用法,正如上文所說(shuō),在注解類上,其實(shí)隱含了很多的事務(wù)屬性參數(shù),Transactional注解類源碼如下。

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public@interface Transactional {

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

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

Propagation propagation() default Propagation.REQUIRED;

Isolation isolation() default Isolation.DEFAULT;

int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

boolean readOnly() default false;

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

 String[] rollbackForClassName() default {};

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

 String[] noRollbackForClassName() default {};
}

下面我們一起來(lái)看看每個(gè)屬性的作用。

屬性

類型

默認(rèn)值

說(shuō)明

transactionManager

String

DEFAULT

事務(wù)管理器

propagation

Propagation枚舉

REQUIRED

事務(wù)傳播屬性

isolation

Isolation枚舉

DEFAULT

事務(wù)隔離級(jí)別

timeout

int

-1

超時(shí)(秒)

readOnly

boolean

false

是否只讀

rollbackFor

Class[]

{}

需要支持回滾的異常類

rollbackForClassName

String[]

{}

需要支持回滾的異常類名

noRollbackFor

Class[]

{}

不需要支持回滾的異常類

noRollbackForClassName

String[]

{}

不需要支持回滾的異常類名

我們重點(diǎn)看看transactionManager、propagation和isolation這三個(gè)參數(shù)屬性值配置,其它參數(shù)基本上見(jiàn)名之意,就不用介紹了。

3.1、事務(wù)管理器屬性

默認(rèn)情況下,不需要我們手動(dòng)配置事務(wù)管理器實(shí)例。如果 Spring 容器中有多個(gè)事務(wù)管理器實(shí)例,比如多數(shù)據(jù)源的情況下,某些場(chǎng)景下,就需要我們手動(dòng)指定事務(wù)管理器實(shí)例。

具體應(yīng)用示例如下:

@Configuration
publicclass TransactionManagerConfigBean {

    @Autowired
    private DataSource dataSource;

    /**
     * 自定義一個(gè)事務(wù)管理器1,同時(shí)作為默認(rèn)事務(wù)管理器
     * @return
     */
    @Bean(name = "txManager1")
    @Primary
    public PlatformTransactionManager txManager1() {
        returnnew DataSourceTransactionManager(dataSource);
    }

    /**
     * 自定義一個(gè)事務(wù)管理器2
     * @return
     */
    @Bean(name = "txManager2")
    public PlatformTransactionManager txManager2() {
        returnnew DataSourceTransactionManager(dataSource);
    }
}

如果需要使用指定的事務(wù)管理器,只需要在@Transactional注解中配置相應(yīng)的參數(shù)即可。

@Service
publicclass ApiService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Transactional(value = "txManager2")
    public void insert(Role role, Menu menu) throws Exception {
        // 新增角色信息
        roleMapper.insert(role);
        // 新增菜單信息
        menuMapper.insert(menu);
    }
}

3.2、事務(wù)傳播屬性

事務(wù)傳播屬性,指的是當(dāng)一個(gè)方法內(nèi)同時(shí)存在多個(gè)事務(wù)的時(shí)候,Spring 如何處理這些事務(wù)的行為。

Spring 支持 7 種事務(wù)傳播方式,Propagation枚舉類支持的屬性值如下:

  • REQUIRED:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)
  • SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行
  • MANDATORY:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則拋出異常
  • REQUIRES_NEW:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起
  • NOT_SUPPORTED:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起
  • NEVER:以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常
  • NESTED:如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則該取值等價(jià)于REQUIRED

如果想要指定事務(wù)傳播行為,可以通過(guò)propagation屬性設(shè)置,例如:

@Transactional(propagation = Propagation.REQUIRED)

Spring 默認(rèn)采用的是REQUIRED屬性值,也就是說(shuō),如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。

這樣設(shè)計(jì)的好處在于:當(dāng)一個(gè)方法存在多個(gè)事務(wù)開啟的操作時(shí),只會(huì)有一個(gè)有效的事務(wù)實(shí)例,可以實(shí)現(xiàn)數(shù)據(jù)的原子性操作。

比如如下示例:

@Service
publicclass ApiService {

    privatestaticfinal Logger LOGGER = LoggerFactory.getLogger(ApiService.class);

    @Autowired
    private RoleService roleService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void save(Role role, Menu menu){
        //手動(dòng)開啟事務(wù)
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
        try {
            // 新增角色信息
            roleService.insert(role);
            // 新增菜單信息
            menuService.insert(menu);
            // 提交事務(wù)
            transactionManager.commit(status);
        } catch (Exception e) {
            // 回滾事務(wù)
            transactionManager.rollback(status);
            LOGGER.error("提交數(shù)據(jù)異常",e);
        }
    }
}
@Service
public class RoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Transactional
    public void insert(Role role){
        roleMapper.insert(role);
    }
}
@Service
publicclass MenuService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void insert(Menu menu){
        transactionTemplate.execute(status -> {
            menuMapper.insert(menu);
            returnnull;
        });
    }
}

當(dāng)調(diào)用ApiService.save()方法時(shí),如果出現(xiàn)異常,所有的操作都會(huì)回滾;反之,提交事務(wù)。

3.3、事務(wù)隔離級(jí)別屬性

事務(wù)隔離級(jí)別,可以簡(jiǎn)單的理解為數(shù)據(jù)庫(kù)的事務(wù)隔離級(jí)別。

從數(shù)據(jù)庫(kù)角度,為了解決多個(gè)事務(wù)操作同一條數(shù)據(jù)產(chǎn)生的并發(fā)問(wèn)題,提出了事務(wù)隔離級(jí)別概念,由低到高依次為 Read uncommitted 、Read committed 、Repeatable read 、Serializable ,這四個(gè)級(jí)別可以逐個(gè)解決臟讀 、不可重復(fù)讀 、幻讀等這幾類問(wèn)題,每個(gè)隔離級(jí)別作用如下:

  • read uncommitted:俗稱讀未提交,指的是一個(gè)事務(wù)還沒(méi)提交時(shí),它做的變更就能被別的事務(wù)看到。
  • Read committed:俗稱讀提交,指的是一個(gè)事務(wù)提交之后,它做的變更才會(huì)被其他事務(wù)看到。
  • Repeatable read:俗稱可重復(fù)讀,指的是一個(gè)事務(wù)執(zhí)行過(guò)程中看到的數(shù)據(jù),總是跟這個(gè)事務(wù)在啟動(dòng)時(shí)看到的數(shù)據(jù)是一致的,同時(shí)當(dāng)其他事務(wù)在未提交時(shí),變更是不可見(jiàn)的。
  • Serializable:俗稱串行化,顧名思義就是對(duì)于同一行記錄,“寫”會(huì)加“寫鎖”,“讀”會(huì)加“讀鎖”。當(dāng)出現(xiàn)讀寫鎖沖突的時(shí)候,后訪問(wèn)的事務(wù)必須等前一個(gè)事務(wù)執(zhí)行完成,才能繼續(xù)執(zhí)行。

在 Spring 中,事務(wù)隔離級(jí)別的設(shè)置可以通過(guò)Isolation枚舉類來(lái)指定,其支持的屬性值如下:

  • DEFAULT:默認(rèn)值,表示使用底層數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別。大部分?jǐn)?shù)據(jù)庫(kù),默認(rèn)隔離級(jí)別為可重復(fù)讀;Mysql 有些例外,采用可重復(fù)讀隔離級(jí)別
  • READ_UNCOMMITTED:對(duì)應(yīng)數(shù)據(jù)庫(kù)中讀未提交的隔離級(jí)別
  • READ_COMMITTED :對(duì)應(yīng)數(shù)據(jù)庫(kù)中讀提交的隔離級(jí)別
  • REPEATABLE_READ :對(duì)應(yīng)數(shù)據(jù)庫(kù)中可重復(fù)讀的隔離級(jí)別
  • SERIALIZABLE:對(duì)應(yīng)數(shù)據(jù)庫(kù)中串行化的隔離級(jí)別

如果想要指定事務(wù)隔離級(jí)別,可以通過(guò)isolation屬性設(shè)置,例如:

@Transactional(isolation = Isolation.DEFAULT)

四、小結(jié)

最后總結(jié)一下,編程式的事務(wù)管理比較靈活,如果當(dāng)前操作非常耗時(shí),可以采用編程式的事務(wù)管理來(lái)提交事務(wù),避免長(zhǎng)事務(wù)影響數(shù)據(jù)庫(kù)性能;其次如果數(shù)據(jù)操作比較簡(jiǎn)單時(shí)間短,可以采用聲明式事務(wù)管理,如果使用不當(dāng),可能會(huì)導(dǎo)致事務(wù)失效,因此在實(shí)際使用中要多加小心。

本文主要圍繞 Spring Boot 事務(wù)管理的使用方式,做了一次知識(shí)內(nèi)容的總結(jié),如果有描述不對(duì)的地方,歡迎留言指出。

五、參考

1.https://www.cnblogs.com/sharpest/p/7995203.html

2.https://blog.csdn.net/MinggeQingchun/article/details/119579941

責(zé)任編輯:武曉燕 來(lái)源: 潘志的技術(shù)筆記
相關(guān)推薦

2024-06-25 08:18:55

2013-04-15 10:59:08

iOS開發(fā)ARC版本說(shuō)明

2019-10-15 10:23:13

服務(wù)器MySQL 數(shù)據(jù)

2022-08-03 08:17:00

Redis事務(wù)內(nèi)存

2017-07-20 16:55:56

Android事件響應(yīng)View源碼分析

2024-05-17 10:05:06

Java機(jī)制應(yīng)用

2022-05-25 08:31:31

ArthasInstrument

2019-07-23 08:55:46

Base64編碼底層

2021-04-07 13:28:21

函數(shù)程序員異步

2015-07-15 17:09:48

HiveHadoop分布式文件系統(tǒng)

2020-10-09 08:15:11

JsBridge

2017-09-05 08:52:37

Git程序員命令

2024-05-10 08:19:59

arthasjava字節(jié)碼

2022-02-21 09:44:45

Git開源分布式

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺(tái)

2019-04-17 15:16:00

Sparkshuffle算法

2021-04-09 08:40:51

網(wǎng)絡(luò)保險(xiǎn)網(wǎng)絡(luò)安全網(wǎng)絡(luò)風(fēng)險(xiǎn)

2021-11-04 10:34:02

JavaScript繼承編程

2025-03-07 08:24:10

Javavolatilecount++
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)