偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Spring事務的一道面試題

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

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

原理

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

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

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

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

1.源碼

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

2.實踐出真知

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

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

幾種事務不生效的用法

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

1.private方法

Spring是通過AOP代理的方式實現(xiàn)事務增強的,但是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.異常被吞掉

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

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

5.非RuntimeException異常

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

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

  • 捕獲異常,然后拋出自定義異常。
  • 自行在@Transactional注解中增加@Transactional(rollbackFor = XxxxxxxException.class)屬性?;蛘咧苯邮褂胷ollbackFor = Exception.class,也就免去了第一步。

6.異步線程的場景

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

7.重災區(qū):在同一個類中調(diào)用本類的方法

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

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

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

一道面試題

以上關于事務不生效的用法都比較好記,只有在同一個類中調(diào)用本類的方法場景下存在多種變種。具體請看這道面試題。請問以下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");
    }
}

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

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

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

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

因為以上代碼中的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業(yè)務

2009-08-11 10:12:07

C#算法

2017-11-21 12:15:27

數(shù)據(jù)庫面試題SQL

2022-04-08 07:52:17

CSS面試題HTML

2009-08-11 15:09:44

一道面試題C#算法

2023-08-01 08:10:46

內(nèi)存緩存

2021-05-31 07:55:44

smartRepeatJavaScript函數(shù)

2021-10-28 11:40:58

回文鏈表面試題數(shù)據(jù)結構

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面試題運行時數(shù)據(jù)

2017-09-13 07:15:10

Python讀寫文件函數(shù)

2021-03-27 10:59:45

JavaScript開發(fā)代碼

2018-04-26 11:23:01

Linuxfork程序

2021-04-13 08:50:21

JS作用域面試題
點贊
收藏

51CTO技術棧公眾號