Spring Boot事務註解全面解析

在Spring Boot應用程序中,事務註解是最常用的註解之一。它可以幫助程序員更好地管理資料庫事務,並提高代碼的可維護性和可測試性。本文將從多個方面對Spring Boot事務註解進行詳細的闡述,包括事務註解回滾、事務註解不生效、事務註解原理、事務註解失效問題、事務註解參數、核心註解等內容。

一、Spring Boot事務註解回滾

Spring Boot事務註解中最常用到的一個功能就是回滾。在默認情況下,當代碼中的一個方法出現異常時,Spring會自動回滾所有對資料庫的修改。例如:

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void saveAll(List userList) {
        for (User user : userList) {
            userRepository.save(user);
        }
        throw new RuntimeException("出現異常,事務回滾");
    }
}

上面的代碼中,當saveAll方法被調用時,如果保存到資料庫時出現異常,Spring將自動回滾所有對資料庫的修改。這是因為saveAll方法上被@Transactional註解所標註。

同時,也可以使用@Transactional註解的rollbackFor屬性來指定哪些異常可以觸發回滾:

@Transactional(rollbackFor = Exception.class)
public void saveAll(List userList) {
    for (User user : userList) {
        userRepository.save(user);
    }
}

上面的代碼中,指定了rollbackFor屬性為Exception.class,表示只要代碼中出現Exception及其子類的異常,都會觸發事務回滾。

二、Spring Boot事物註解不生效

事務註解不生效可能是讓程序員最為頭疼的問題之一。以下列出一些事務註解不生效的原因:

1. 不是public方法

Spring事務默認只對public方法有效,因為只有public方法才能被外部調用。如果使用事務註解來註解一個非public方法,那麼這個事務註解將不會生效。

@Component
public class UserService {

    @Autowired
    private UserDao userDao;

    @Transactional
    protected void save(User user) {
        userDao.save(user);
    }
}

上面的代碼中,save方法是被protected修飾的。因此,save方法上加的@Transactional註解將無效。

2. 方法內部調用

如果在方法內部調用了另一個帶有@Transactional註解的方法,事務註解將不會生效。這是因為Spring事務是基於AOP來實現的。在方法內部調用另一個方法,會繞過AOP代理。因此如果要使事務註解生效,必須在外部調用方法。

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    @Transactional
    public void saveAndDelete(User userToDelete, User userToSave) {
        userDao.delete(userToDelete);
        save(userToSave);//save方法上有@Transactional註解
    }

    @Transactional
    public void save(User user) {
        userDao.save(user);
    }
}

上面的代碼中,如果調用saveAndDelete方法,只有saveAndDelete方法上的@Transactional註解會生效,而save方法上的@Transactional註解將無效。

3. 異常被捕獲

如果在事務方法內部捕獲了異常,並處理了異常,那麼事務將正常提交,不會回滾。

@Autowired
private UserDao userDao;

@Transactional
public void save(User user) {
    try {
        userDao.save(user);
        throw new RuntimeException("出現異常,但已被處理");
    } catch (Exception e) {
        //異常處理
    }
}

上面的代碼中,出現異常會被捕獲並進行了處理。因此,@Transactional註解將不會回滾事務。

三、Spring Boot事務註解原理

在Spring Boot中,事務註解的原理是基於AOP(面向切面編程)的。也就是說,對於帶有@Transactional註解的方法,在運行時會被動態地生成一個代理類,並將該方法被代理。當執行代理方法時,代理方法會判斷是否有事務正在進行,如果沒有,則開啟一個新事務;如果有,則將該方法的操作放入當前事務中。最後,執行完代理方法時,會判斷是否有異常發生,如果有,則回滾事務,否則提交事務。

四、Spring Boot事務註解失效問題

除了上面提到的事務註解不生效的原因之外,下面列舉一些其他的事務註解失效問題:

1. 異常不聲明拋出類型

聲明拋出的異常類型不能夠衝突,否則事務註解將失效。

@Transactional
public void save(User user) throws Exception {
    userDao.save(user);
    try {
        throw new Exception("業務異常");
    } catch (Exception e) {
        throw new Exception("異常");
    }
}

上面的代碼中,save方法聲明拋出Exception異常。但是,在try-catch中,又拋出了另一個Exception異常。這將導致布滿Spring默認的事務註解失效。

2. Redis註解與事務註解同時使用

在Spring Boot應用程序中,有時會使用Redis來緩存數據。如果在同一個方法中同時使用Redis註解和事務註解,可能會導致事務註解失效。

@Transactional
public void saveAndCache(User user) {
    userDao.save(user);
    redisTemplate.opsForValue().set(user.getId(), user);
}

上面的代碼中,在同一個方法中使用了@Transactional註解和Redis操作,這將導致事務註解失效。

為了解決這個問題,可以使用Spring提供的專門的Redis事務註解。將Redis操作放到一個單獨的方法中,並使用@RedisTransaction註解標註該方法,然後在需要訪問緩存的其他方法中調用該方法:

@Transactional
public void saveAndCache(User user) {
    userDao.save(user);
    cache(user);
}

@RedisTransaction
public void cache(User user) {
    redisTemplate.opsForValue().set(user.getId(), user);
}

五、Spring Boot事務註解加了沒用

如果我們在代碼中添加了@Transactional註解,但是並沒有看到任何事務被開啟或者提交,我們需要檢查以下幾個事項:

1. 開啟事務的方法名是否正確

在使用註解的時候是通過方法進行控制的,因此,事務註解加在的方法是一定要正確的。如果註解加在了一個不執行的方法上,那麼註解就是毫無作用的。

2. 檢查所在的類是否被代理成功

如果事務代理並沒有對一個類進行代理,那麼在這個類中加上@Transactional也是沒有卵用的。

3. 檢查事務是否已經被提交或回滾

如果事務已經被提交或回滾,那麼為了保證代碼的正確性,事務代理就不會執行任何操作了。在這種情況下,我們可以在日誌中查看是否有相關的記錄,以確定事務是否被提交或回滾。

六、Spring Boot事物註解失效場景

下面列舉一些常見的場景,可能導致Spring Boot事務註解失效:

1. 使用JdbcTemplate訪問資料庫

如果在使用Spring Boot JdbcTemplate訪問資料庫時,沒有使用Spring Boot提供的JdbcTemplate事務註解,可能會導致事務註解失效。

@Autowired
private JdbcTemplate jdbcTemplate;

@Transactional
public void save(User user) {
    jdbcTemplate.update("insert into user(username, password) values(?, ?)", user.getUsername(), user.getPassword());
}

上面的代碼中,雖然save方法上標註了@Transactional註解,但是jdbcTemplate是通過注入的方式獲得的,沒有使用JdbcTemplate事務註解,因此,事務註解將失效。

2. 多數據源情況下

在多數據源情況下,鐵線事務註解可能會失效。因為事務註解是基於AOP實現的,必須確保所有的操作都在同一個事務中進行。

@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
    return DataSourceBuilder.create().build();
}

@Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

@Bean(name = "secondaryJdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

@Transactional
public void save(User user) {
    primaryJdbcTemplate.update("insert into user(username, password) values(?, ?)", user.getUsername(), user.getPassword());
    secondaryJdbcTemplate.update("insert into user(username, password) values(?, ?)", user.getUsername(), user.getPassword());
}

上面的代碼中,save方法中同時使用了兩個數據源的JdbcTemplate進行訪問。由於每個JdbcTemplate都有一個事務,因此@Transactional註解將失效。

七、Spring Boot事務註解參數

Spring Boot事務註解提供了一些參數,可以用來進一步控制事務的行為:

1. isolation

表示事務的隔離級別。常用的有READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。其中,SERIALIZABLE級別可以最大程度地保證數據的一致性,但是對資料庫性能的影響最大。

@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateCUser(User user1, User user2) {
    //...
}

2. timeout

表示事務的超時時間,單位是秒。如果事務在指定的時間內沒有執行完,就會被強制回滾。

@Transactional(timeout = 10)
public void save(User user) {
    //...
}

3. readOnly

表示事務是否為只讀。如果為只讀,那麼事務中只能進行查詢操作,不能進行修改操作。這可以提高查詢效率,減少鎖定時間。

@Transactional(readOnly = true)
public List getAllUser() {
    //...
}

4. propagation

表示事務的傳播行為。當一個事務方法調用另一個事務方法時,就會使用到傳播行為。常用的有REQUIRED、REQUIRES_NEW、NESTED等。其中,REQUIRED是默認值。REQUIRES_NEW表示如果當前方法已有事務,則會掛起當前事務並重新開啟一個新事務執行;而NESTED則表示如果當前方法已有事務,則嵌套在當前事務中執行。

@Transactional(propagation = Propagation.REQUIRED)
public void saveUserAndRole(User user, Role role) {
    saveUser(user);
    saveRole(role);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveUser(User user) {
    //...
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveRole(Role role) {
    //...
}

八、SpringBoot核心註解

最後,本文列舉了一

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/183739.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-25 05:51
下一篇 2024-11-25 05:52

相關推薦

  • Python應用程序的全面指南

    Python是一種功能強大而簡單易學的編程語言,適用於多種應用場景。本篇文章將從多個方面介紹Python如何應用於開發應用程序。 一、Web應用程序 目前,基於Python的Web…

    編程 2025-04-29
  • Spring Boot 集成 Jacoco

    本文將從以下幾個方面介紹如何在 Spring Boot 中集成 Jacoco:1、Jacoco 概述;2、Spring Boot 集成 Jacoco 的配置;3、生成 Jacoco…

    編程 2025-04-29
  • Spring Boot中發GET請求參數的處理

    本文將詳細介紹如何在Spring Boot中處理GET請求參數,並給出完整的代碼示例。 一、Spring Boot的GET請求參數基礎 在Spring Boot中,處理GET請求參…

    編程 2025-04-29
  • Python zscore函數全面解析

    本文將介紹什麼是zscore函數,它在數據分析中的作用以及如何使用Python實現zscore函數,為讀者提供全面的指導。 一、zscore函數的概念 zscore函數是一種用於標…

    編程 2025-04-29
  • Hibernate註解聯合主鍵 如何使用

    解答:Hibernate的註解方式可以用來定義聯合主鍵,使用@Embeddable和@EmbeddedId註解。 一、@Embeddable和@EmbeddedId註解 在Hibe…

    編程 2025-04-29
  • 全面解讀數據屬性r/w

    數據屬性r/w是指數據屬性的可讀/可寫性,它在程序設計中扮演著非常重要的角色。下面我們從多個方面對數據屬性r/w進行詳細的闡述。 一、r/w的概念 數據屬性r/w即指數據屬性的可讀…

    編程 2025-04-29
  • Python計算機程序代碼全面介紹

    本文將從多個方面對Python計算機程序代碼進行詳細介紹,包括基礎語法、數據類型、控制語句、函數、模塊及面向對象編程等。 一、基礎語法 Python是一種解釋型、面向對象、動態數據…

    編程 2025-04-29
  • 如何在Spring Cloud中整合騰訊雲TSF

    本篇文章將介紹如何在Spring Cloud中整合騰訊雲TSF,並提供完整的代碼示例。 一、TSF簡介 TSF (Tencent Serverless Framework)是騰訊雲…

    編程 2025-04-29
  • Java Hmily分散式事務解決方案

    分散式系統是現在互聯網公司架構中的必備項,但隨著業務的不斷擴展,分散式事務的問題也日益凸顯。為了解決分散式事務問題,Java Hmily分散式事務解決方案應運而生。本文將對Java…

    編程 2025-04-28
  • 如何使用Spring Boot ElasticJob進行配置覆蓋

    本文將詳細介紹如何使用Spring Boot ElasticJob進行配置覆蓋。 一、目錄結構 我們需要準備兩個目錄,分別是「elastic-job-lite-spring-boo…

    編程 2025-04-28

發表回復

登錄後才能評論