成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring事務的一道面試題

開發
每次聊起Spring事務,好像很熟悉,又好像很陌生。本篇通過一道面試題和一些實踐,來拆解幾個Spring事務的常見坑點。

每次聊起Spring事務,好像很熟悉,又好像很陌生。本篇通過一道面試題和一些實踐,來拆解幾個Spring事務的常見坑點。

原理

Spring事務的原理是:通過AOP切面的方式實現的,也就是通過代理模式去實現事務增強。

具體過程是:對包含@Transactional注解的方法進行攔截,然后重寫,重新在方法里加入異常回滾的邏輯。而且,每個線程都是獨立管理自己的事務,相互隔離。

原理簡單,使用起來也簡單,也就是在方法上打上@Transactional注解,然后事務就正常生效了。也很少有人去驗證異常情況下是否能真正的回滾。

Spring事務讓我熟悉的地方是哪哪看起來都簡單,讓我陌生的地方使用時的變種較多,有時候莫名其妙的不生效。

1.源碼

以上原理的相關源碼如下:

2.實踐出真知

但是 [半支煙] 偶爾會在編碼過程中發現有些場景下的事務是失效的,總有些情況讓你想不到,總有一些坑點等你去跳。

[半支煙] 覺得驗證事務的最好方式就是:記住基本原則 + 動手實踐。記住基本原則可以快速處理常規問題,動手實踐可以驗證偏門問題或者不確定的問題。

幾種事務不生效的用法

如下是常見的幾種Spring事務不生效的用法,有空的讀者一定要牢記,對日常編碼很有幫助,同時面試時也能說幾句。

1.private方法

Spring是通過AOP代理的方式實現事務增強的,但是private方法無法被代理,所以在private方法上打@Transactional注解是不生效的。

2.final、static修飾的方法

和private方法類似,final和static修飾的方法也無法被代理,所以@Transactional注解也不生效。

因為,static是屬于類方法,final修飾的方法無法被重寫,自然也就無法植入事務增強代碼。

3.Bean對象沒有被Spring托管

某個類一定要被Spring托管,那才能通過@Transactional注解去增強事務。如果只有@Transactional注解,而沒有把類交給Spring托管,事務也是不生效的。類似如下情況:

// 此處沒有@Service注解,此類不被spring托管,及時有@Transactional也不生效
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public final void createAndUpdateUser() {
        createUser();
        updateUserById();
    }

    public void createUser() {
        User user = new User();
        user.setId(2L);
        user.setName("test2");
        user.setEmail("test2" + "@test.com");
        userMapper.insert(user);
        System.out.println("create user");
    }

    public void updateUserById() {
        User user = userMapper.findById(1L);
        user.setName("admin1");
        userMapper.update(user);
        int i = 1 / 0; // 此處會拋出異常
        System.out.println("update user");
    }
}

4.異常被吞掉

如果在業務代碼里,通過try......catch捕獲了異常,同時又沒有繼續拋出異常時,Spring事務也是不生效的。

因為代理增強的邏輯就是要發現了異常,才能回滾事務。如果異常被方法本身吞掉了,則代理會認為沒有異常,從而無法回滾。

5.非RuntimeException異常

Spring事務默認會回滾RuntimeException 及其子類,以及 Error 類型的異常。如果是其余異常,則不會回滾。源碼處可見:

這種非RuntimeException異常場景下,需要做2個動作從而保證事務回滾。

  • 捕獲異常,然后拋出自定義異常。
  • 自行在@Transactional注解中增加@Transactional(rollbackFor = XxxxxxxException.class)屬性。或者直接使用rollbackFor = Exception.class,也就免去了第一步。

6.異步線程的場景

多個線程的場景下,只需要牢記每個線程只管理自己的事務即可。每個線程都有一個獨立的事務上下文,存在ThreadLocal中,所以事務信息在不同線程之間是隔離的。

7.重災區:在同一個類中調用本類的方法

這個失效場景,是最容易出錯的,而且變種還多。在同一個類中調用本類的方法時,牢記以下2點,即可破局:

  • 是否會開啟事務依賴此類的第一個被外部調用的方法。如果此類的第一個被外部調用的方法有@Transactional注解,那事務生效。
  • 調用自己內部方法時,采用的是this.xxxMethod()的方式,這種方式是不會走AOP代理的,所以被調用的內部方法的@Transactional注解不生效。

如果確實需要調用內部方法,并且要事務生效的話,那只能將被調用的內部方法獨立到新的類中,同時交給Spring管理。

一道面試題

以上關于事務不生效的用法都比較好記,只有在同一個類中調用本類的方法場景下存在多種變種。具體請看這道面試題。請問以下createAndUpdateUser方法的事務生效嗎?

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Transactional
    public final void createAndUpdateUser() { //注意這里有final修飾
        createUser();
        updateUserById();
    }

    @Transactional
    public void createUser() {
        User user = new User();
        user.setId(2L);
        user.setName("test2");
        user.setEmail("test2" + "@test.com");
        userMapper.insert(user);
        System.out.println("create user");
    }


    @Transactional(rollbackFor = Exception.class)
    public void updateUserById() {
        User user = userMapper.findById(1L);
        user.setName("admin1");
        userMapper.update(user);
        int i = 1 / 0; // 此處會拋出異常
        System.out.println("update user");
    }
}

如果按照重災區:在同一個類中調用本類的方法里提到的2個原則,則事務全部生效。

如果按照final、static修飾的方法里提到的原則,則事務全部不生效。

那結果如何呢?結果是以上方法的事務全部生效。

為什么呢?這里在補充一個原則:final修飾的方法如果帶上@Transactional注解,事務情況按照被調用的方法自身的事務托管情況而定。

因為以上代碼中的createUser方法和updateUserById方法,都有@Transactional注解,所以都生效。

這種特殊情況也實在是讓人瞠目,不過只需要牢記以上幾種不生效的用法即可,誰沒事兒寫這種@Transactional + final的代碼呢?除了面試會問......

總結

本篇主要聊了幾種事務不生效的用戶,有興趣的讀者可以記一下。同時,還出了一道特殊場景的面試題,供讀者自行實踐。希望對你有幫助!

責任編輯:趙寧寧 來源: 程序員半支煙
相關推薦

2018-03-06 15:30:47

Java面試題

2011-05-23 11:27:32

面試題面試java

2009-08-11 14:59:57

一道面試題C#算法

2023-02-04 18:24:10

SeataJava業務

2009-08-11 10:12:07

C#算法

2017-11-21 12:15:27

數據庫面試題SQL

2022-04-08 07:52:17

CSS面試題HTML

2009-08-11 15:09:44

一道面試題C#算法

2023-08-01 08:10:46

內存緩存

2021-05-31 07:55:44

smartRepeatJavaScript函數

2021-10-28 11:40:58

回文鏈表面試題數據結構

2022-02-08 18:09:20

JS引擎解析器

2015-09-02 14:09:19

面試題程序設計

2017-03-10 09:33:16

JavaScript類型

2011-03-02 10:58:16

SQL server入門面試題

2021-03-16 05:44:26

JVM面試題運行時數據

2017-09-13 07:15:10

Python讀寫文件函數

2021-03-27 10:59:45

JavaScript開發代碼

2018-04-26 11:23:01

Linuxfork程序

2021-04-13 08:50:21

JS作用域面試題
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久99久久99精品免视看婷婷 | 性做久久久久久免费观看欧美 | 国产亚洲一区二区三区在线观看 | 国产一区二区视频在线观看 | 麻豆亚洲 | 日韩中文字幕 | 久久精品国产精品青草 | 国产成人99久久亚洲综合精品 | 午夜在线影院 | 精品一区二区三区入口 | 北条麻妃99精品青青久久 | 国产激情视频网址 | 亚洲在线| 亚洲一本 | 欧美日韩在线播放 | 男女羞羞的网站 | 一区影院 | 少妇特黄a一区二区三区88av | yiren22 亚洲综合 | 日韩欧美网 | 精品一区二区电影 | 欧美日韩高清免费 | 国产成人精品午夜视频免费 | 成年人在线观看视频 | 伊人国产精品 | 亚洲一区二区视频 | 国产精品成人一区二区三区夜夜夜 | 国产乱码精品一区二区三区中文 | 国产一区二区三区高清 | 国产在线观看 | 日韩欧美国产一区二区三区 | 亚洲精品日韩精品 | 亚洲国产情侣自拍 | 久久久精品日本 | 日本高清中文字幕 | 一级黄色播放 | www.精品一区 | 在线观看成年人视频 | 亚洲一级av毛片 | 日韩欧美精品 | 欧美成人免费 |