中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot事務配置管理是什么

發布時間:2021-07-19 09:56:39 來源:億速云 閱讀:147 作者:chen 欄目:編程語言

本篇內容介紹了“Spring Boot事務配置管理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!


 

1. 事務相關

場景:我們在開發企業應用時,由于數據操作在順序執行的過程中,線上可能有各種無法預知的問題,任何一步操作都有可能發生異常,異常則會導致后續的操作無法完成。此時由于業務邏輯并未正確的完成,所以在之前操作過數據庫的動作并不可靠,需要在這種情況下進行數據的回滾。

事務的作用就是為了保證用戶的每一個操作都是可靠的,事務中的每一步操作都必須成功執行,只要有發生異常就回退到事務開始未進行操作的狀態。這很好理解,轉賬、購票等等,必須整個事件流程全部執行完才能人為該事件執行成功,不能轉錢轉到一半,系統死了,轉賬人錢沒了,收款人錢還沒到。

事務管理是 Spring Boot 框架中最為常用的功能之一,我們在實際應用開發時,基本上在 service 層處理業務邏輯的時候都要加上事務,當然了,有時候可能由于場景需要,也不用加事務(比如我們就要往一個表里插數據,相互沒有影響,插多少是多少,不能因為某個數據掛了,把之前插的全部回滾)。

 

2. Spring Boot 事務配置

 

2.1 依賴導入

在 Spring Boot 中使用事務,需要導入 mysql 依賴:

<dependency>
 <groupId>org.mybatis.spring.boot</groupId>
 <artifactId>mybatis-spring-boot-starter</artifactId>
 <version>1.3.2</version>
</dependency>
 

導入了 mysql 依賴后,Spring Boot 會自動注入 DataSourceTransactionManager,我們不需要任何其他的配置就可以用 @Transactional 注解進行事務的使用。關于 mybatis 的配置,在上一節課中已經說明了,這里還是使用上一節課中的 mybatis 配置即可。

 

2.2 事務的測試

我們首先在數據庫表中插入一條數據:

iduser_namepassword
1倪升武123456

然后我們寫一個插入的 mapper:

public interface UserMapper {

    @Insert("insert into user (user_name, password) values (#{username}, #{password})")
    Integer insertUser(User user);
}
 

OK,接下來我們來測試一下 Spring Boot 中的事務處理,在 service 層,我們手動拋出個異常來模擬實際中出現的異常,然后觀察一下事務有沒有回滾,如果數據庫中沒有新的記錄,則說明事務回滾成功。

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    @Transactional
    public void isertUser(User user) {
        // 插入用戶信息
        userMapper.insertUser(user);
        // 手動拋出異常
        throw new RuntimeException();
    }
}
 

我們來測試一下:

@RestController
public class TestController {

    @Resource
    private UserService userService;

    @PostMapping("/adduser")
    public String addUser(@RequestBody User user) throws Exception {
        if (null != user) {
            userService.isertUser(user);
            return "success";
        } else {
            return "false";
        }
    }
}
 

我們使用 postman 調用一下該接口,因為在程序中拋出了個異常,會造成事務回滾,我們刷新一下數據庫,并沒有增加一條記錄,說明事務生效了。事務很簡單,我們平時在使用的時候,一般不會有多少問題,但是并不僅僅如此……

 

3. 常見問題總結

從上面的內容中可以看出,Spring Boot 中使用事務非常簡單,@Transactional 注解即可解決問題,說是這么說,但是在實際項目中,是有很多小坑在等著我們,這些小坑是我們在寫代碼的時候沒有注意到,而且正常情況下不容易發現這些小坑,等項目寫大了,某一天突然出問題了,排查問題非常困難,到時候肯定是抓瞎,需要費很大的精力去排查問題。

這一小節,我專門針對實際項目中經常出現的,和事務相關的細節做一下總結,希望讀者在讀完之后,能夠落實到自己的項目中,能有所受益。

 

3.1 異常并沒有被 ”捕獲“ 到

首先要說的,就是異常并沒有被 ”捕獲“ 到,導致事務并沒有回滾。我們在業務層代碼中,也許已經考慮到了異常的存在,或者編輯器已經提示我們需要拋出異常,但是這里面有個需要注意的地方:并不是說我們把異常拋出來了,有異常了事務就會回滾,我們來看一個例子:

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;
    
    @Override
    @Transactional
    public void isertUser2(User user) throws Exception {
        // 插入用戶信息
        userMapper.insertUser(user);
        // 手動拋出異常
        throw new SQLException("數據庫異常");
    }
}
 

我們看上面這個代碼,其實并沒有什么問題,手動拋出一個 SQLException 來模擬實際中操作數據庫發生的異常,在這個方法中,既然拋出了異常,那么事務應該回滾,實際卻不如此,讀者可以使用我源碼中 controller 的接口,通過 postman 測試一下,就會發現,仍然是可以插入一條用戶數據的。

那么問題出在哪呢?因為 Spring Boot 默認的事務規則是遇到運行異常(RuntimeException)和程序錯誤(Error)才會回滾。比如上面我們的例子中拋出的 RuntimeException 就沒有問題,但是拋出 SQLException 就無法回滾了。針對非檢測異常,如果要進行事務回滾的話,可以在 @Transactional 注解中使用 rollbackFor 屬性來指定異常,比如 @Transactional(rollbackFor = Exception.class),這樣就沒有問題了,所以在實際項目中,一定要指定異常。

 

3.2 異常被 ”吃“ 掉

這個標題很搞笑,異常怎么會被吃掉呢?還是回歸到現實項目中去,我們在處理異常時,有兩種方式,要么拋出去,讓上一層來捕獲處理;要么把異常 try catch 掉,在異常出現的地方給處理掉。就因為有這中 try...catch,所以導致異常被 ”吃“ 掉,事務無法回滾。我們還是看上面那個例子,只不過簡單修改一下代碼:

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void isertUser3(User user) {
        try {
            // 插入用戶信息
            userMapper.insertUser(user);
            // 手動拋出異常
            throw new SQLException("數據庫異常");
        } catch (Exception e) {
   // 異常處理邏輯
        }
    }
}
 

讀者可以使用我源碼中 controller 的接口,通過 postman 測試一下,就會發現,仍然是可以插入一條用戶數據,說明事務并沒有因為拋出異常而回滾。這個細節往往比上面那個坑更難以發現,因為我們的思維很容易導致 try...catch 代碼的產生,一旦出現這種問題,往往排查起來比較費勁,所以我們平時在寫代碼時,一定要多思考,多注意這種細節,盡量避免給自己埋坑。

那這種怎么解決呢?直接往上拋,給上一層來處理即可,千萬不要在事務中把異常自己 ”吃“ 掉。

 

3.3 事務的范圍

事務范圍這個東西比上面兩個坑埋的更深!我之所以把這個也寫上,是因為這是我之前在實際項目中遇到的,該場景在這個課程中我就不模擬了,我寫一個 demo 讓大家看一下,把這個坑記住即可,以后在寫代碼時,遇到并發問題,就會注意這個坑了,那么這節課也就有價值了。

我來寫個 demo:

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void isertUser4(User user) {
        // 實際中的具體業務……
        userMapper.insertUser(user);
    }
}
 

可以看到,因為要考慮并發問題,我在業務層代碼的方法上加了個 synchronized 關鍵字。我舉個實際的場景,比如一個數據庫中,針對某個用戶,只有一條記錄,下一個插入動作過來,會先判斷該數據庫中有沒有相同的用戶,如果有就不插入,就更新,沒有才插入,所以理論上,數據庫中永遠就一條同一用戶信息,不會出現同一數據庫中插入了兩條相同用戶的信息。

但是在壓測時,就會出現上面的問題,數據庫中確實有兩條同一用戶的信息,分析其原因,在于事務的范圍和鎖的范圍問題。

從上面方法中可以看到,方法上是加了事務的,那么也就是說,在執行該方法開始時,事務啟動,執行完了后,事務關閉。但是 synchronized 沒有起作用,其實根本原因是因為事務的范圍比鎖的范圍大。也就是說,在加鎖的那部分代碼執行完之后,鎖釋放掉了,但是事務還沒結束,此時另一個線程進來了,事務沒結束的話,第二個線程進來時,數據庫的狀態和第一個線程剛進來是一樣的。即由于mysql Innodb引擎的默認隔離級別是可重復讀(在同一個事務里,SELECT的結果是事務開始時時間點的狀態),線程二事務開始的時候,線程一還沒提交完成,導致讀取的數據還沒更新。第二個線程也做了插入動作,導致了臟數據。

這個問題可以避免,第一,把事務去掉即可(不推薦);第二,在調用該 service 的地方加鎖,保證鎖的范圍比事務的范圍大即可。

 

4. 總結

本章主要總結了 Spring Boot 中如何使用事務,只要使用 @Transactional 注解即可使用,非常簡單方便。除此之外,重點總結了三個在實際項目中可能遇到的坑點,這非常有意義,因為事務這東西不出問題還好,出了問題比較難以排查,所以總結的這三點注意事項,希望能幫助到開發中的朋友。

“Spring Boot事務配置管理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

通辽市| 双柏县| 巴彦县| 余姚市| 四川省| 东乡| 类乌齐县| 体育| 灵山县| 增城市| 太和县| 泰和县| 深水埗区| 海晏县| 孟津县| 金坛市| 榆社县| 惠东县| 咸阳市| 临邑县| 延吉市| 潼关县| 平泉县| 内黄县| 贡嘎县| 马公市| 忻州市| 石狮市| 襄城县| 莒南县| 同江市| 濮阳市| 江门市| 张家港市| 固阳县| 大安市| 灌南县| 萍乡市| 德阳市| 渑池县| 康平县|