SpringBoot 快速開啟事務(附常見坑點)


序言:此前,我們主要通過XML配置Spring來托管事務。在SpringBoot則非常簡單,只需在業務層添加事務注解(@Transactional )即可快速開啟事務。雖然事務很簡單,但對於數據方面是需要謹慎對待的,識別常見坑點對我們開發有幫助。

1. 引入依賴

<!--依賴管理 -->
    <dependencies>
        <dependency> <!--添加Web依賴 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency> <!--添加Mybatis依賴 -->
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency><!--添加MySQL驅動依賴 -->
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency><!--添加Test依賴 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

 

2. 添加配置

主要是配置數據源和開啟Mybatis的自動駝峰映射

@SpringBootApplication
public class MybatisTransactionApplication {

    public static void main(String[] args) {
        //1.初始化
        SpringApplication application=  new SpringApplication(MybatisTransactionApplication.class);

        //2.添加數據源
        Map<String,Object> map = new HashMap<>();
        map.put("spring.datasource.url","jdbc:mysql://localhost:3306/socks?useSSL=false");
        map.put("spring.datasource.username","root");
        map.put("spring.datasource.password","root");

        //3.開啟駝峰映射 (Such as account_id ==> accountId)
        map.put("mybatis.configuration.map-underscore-to-camel-case",true);
        application.setDefaultProperties(map);

        //4.啟動應用
        application.run(args);
    }
}

 

3. 添加數據庫記錄

打開 Navicat 的查詢窗口,然后執行以下SQL:

DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `account_id` varchar(30) ,
  `account_name` varchar(30),
  `balance` decimal(20,2),
  PRIMARY KEY (`account_id`)
);

insert into account values ('1','admin','1000.25');

 

執行完畢后,可以查詢到賬戶數據,如圖:

 
 

4. 編寫代碼

以操作賬戶金額為例,模擬正常操作金額提交事務,以及發生異常回滾事務。
其中控制層代碼如下:

package com.hehe.controller;

@RestController
public class AccountController {

    @SuppressWarnings("all")
    @Autowired
    AccountService accountService;

    @GetMapping("/")
    public Account getAccount() {
        //查詢賬戶
        return accountService.getAccount();
    }

    @GetMapping("/add")
    public Object addMoney() {
        try {
            accountService.addMoney();
        } catch (Exception e) {
            return "發生異常了:" + accountService.getAccount();
        }
        return getAccount();
    }
}

 

在業務層使用 @Transactional 開啟事務,執行數據庫操作后拋出異常。具體代碼如下:

package com.hehe.service;

@Service
public class AccountService {

    @SuppressWarnings("all")
    @Autowired
    AccountMapper accountMapper;

    public Account getAccount() {
        return accountMapper.getAccount();
    }

    @Transactional
    public void addMoney() throws Exception {
        //先增加余額
        accountMapper.addMoney();
        //然后遇到故障
        throw new RuntimeException("發生異常了..");
    }
}

 

數據庫層就很簡單了,我們通過注解來實現賬戶數據的查詢,具體如下:

package com.hehe.mapper;

@Mapper
public interface AccountMapper {

    @Select("select * from account where account_id=1")
    Account getAccount();

    @Update("update account set balance = balance+100 where account_id=1")
    void addMoney();
}

 

其中 Account 實體對象如下:

package com.hehe.pojo;

public class Account {

    private String accountId;
    private String accountName;
    private BigDecimal balance;

    // Override toString Method ..
    // Getter & Setters  ..
}

 

5. 測試事務

啟動應用,訪問 http://localhost:8080 ,可以看到賬戶數據,如下:

 
 

然后訪問 http://localhost:8080/add ,可以看到賬戶余額並沒有增加,如下: 也就是說事務開啟成功,數據得到回滾。

 
 

6. 常見坑點

使用事務注解@Transactional 之前,應該先了解它的相關屬性,避免在實際項目中踩中各種各樣的坑點。

常見坑點1:遇到檢測異常時,事務默認不回滾。

例如下面這段代碼,賬戶余額依舊增加成功,並沒有因為后面遇到SQLException(檢測異常)而進行事務回滾!!

 @Transactional
    public void addMoney() throws Exception {
        //先增加余額
        accountMapper.addMoney();
        //然后遇到故障
        throw new SQLException("發生異常了..");
    }

 

原因分析:因為Spring的默認的事務規則是遇到運行異常(RuntimeException及其子類)和程序錯誤(Error)才會進行事務回滾,顯然SQLException並不屬於這個范圍。如果想針對檢測異常進行事務回滾,可以在@Transactional 注解里使用
rollbackFor 屬性明確指定異常。例如下面這樣,就可以正常回滾:

 @Transactional(rollbackFor = Exception.class)
    public void addMoney() throws Exception {
        //先增加余額
        accountMapper.addMoney();
        //然后遇到故障
        throw new SQLException("發生異常了..");
    }

 

常見坑點2: 在業務層捕捉異常后,發現事務不生效。

這是許多新手都會犯的一個錯誤,在業務層手工捕捉並處理了異常,你都把異常“吃”掉了,Spring自然不知道這里有錯,更不會主動去回滾數據。例如:下面這段代碼直接導致增加余額的事務回滾沒有生效。

 @Transactional
    public void addMoney() throws Exception {
        //先增加余額
        accountMapper.addMoney();
        //謹慎:盡量不要在業務層捕捉異常並處理
        try {
            throw new SQLException("發生異常了..");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

 

不要小瞧了這些細節,往前暴露異常很大程度上很能夠幫我們快速定位問題,而不是經常在項目上線后出現問題,卻無法刨根知道哪里報錯。

推薦做法:若非實際業務要求,則在業務層統一拋出異常,然后在控制層統一處理。

    @Transactional
    public void addMoney() throws Exception {
        //先增加余額
        accountMapper.addMoney();
        //推薦:在業務層將異常拋出
        throw new RuntimeException("發生異常了..");
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM