Spring Boot的測試類中使用 @Transactional 注解
前言
我的數(shù)據(jù)庫中有一列數(shù)據(jù)需要根據(jù)不同條件update為不同的狀態(tài)值,我直接從ServiceImpl中復(fù)制了一個方法到Test中,修改完方法體中的幾行代碼后,執(zhí)行Test,控制臺打印了對應(yīng)的update語句,但是數(shù)據(jù)庫中該列的狀態(tài)沒有發(fā)生變化。原因就是復(fù)制過去的方法上帶了 @Transactional 注解,我直接加了一個@Test就開始執(zhí)行,導(dǎo)致事務(wù)回滾了。
現(xiàn)在來補(bǔ)一下相關(guān)知識。
在 Spring Boot 的測試類中使用 @Transactional 注解是一個常見且推薦的做法,但它的行為與你在生產(chǎn)代碼中使用 @Transactional 有所不同,尤其是在執(zhí)行修改 SQL(如 INSERT、UPDATE、DELETE)時。以下是詳細(xì)解釋:
1. 默認(rèn)行為:事務(wù)回滾
當(dāng)你在 Spring Boot 測試類(或測試方法)上使用 @Transactional 注解時,默認(rèn)情況下,整個測試方法在一個事務(wù)中執(zhí)行,并且在測試方法結(jié)束后,事務(wù)會自動回滾(rollback) ,而不是提交(commit)。
這意味著:
- 你在測試中執(zhí)行的修改 SQL(如
UPDATE user SET name = 'test' WHERE id = 1)會生效于當(dāng)前事務(wù)內(nèi)的數(shù)據(jù)庫操作。 - 其他數(shù)據(jù)庫操作(如查詢)能看到這些修改。
- 但一旦測試方法執(zhí)行完畢,Spring 會自動回滾該事務(wù),所有對數(shù)據(jù)庫的修改都不會永久保存到數(shù)據(jù)庫中。
2. 為什么這樣設(shè)計(jì)?
這是為了保證測試的獨(dú)立性和可重復(fù)性:
- 每個測試運(yùn)行后,數(shù)據(jù)庫狀態(tài)恢復(fù)到初始狀態(tài),不會影響其他測試。
- 避免測試之間產(chǎn)生副作用。
- 無需手動清理數(shù)據(jù)庫數(shù)據(jù)。
3. 示例代碼
@SpringBootTest
@Transactional
class UserServiceTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
void testUpdateUser() {
// 查詢原始數(shù)據(jù)
User user = userRepository.findById(1L).orElseThrow();
String originalName = user.getName();
// 執(zhí)行修改 SQL(通過 Service 或直接 JPA)
userService.updateUserName(1L, "NewName");
// 在當(dāng)前事務(wù)中可以查到修改
User updatedUser = userRepository.findById(1L).orElseThrow();
assertEquals("NewName", updatedUser.getName());
// 測試結(jié)束,@Transactional 會導(dǎo)致事務(wù)回滾
// 數(shù)據(jù)庫中 id=1 的用戶姓名仍為 originalName
}
}在這個例子中,updateUserName 方法執(zhí)行的 SQL 修改在測試方法內(nèi)部是可見的,但測試結(jié)束后,數(shù)據(jù)庫不會真正更新。
4. 如何讓修改真正提交?
如果你希望某個測試的修改真正提交到數(shù)據(jù)庫(比如集成測試或性能測試),有以下幾種方式:
方法一:移除@Transactional
@SpringBootTest
// 不加 @Transactional,每次修改都會提交
class IntegrationTest {
@Test
void testPersistData() {
// 修改會真正寫入數(shù)據(jù)庫
}
}
方法二:使用@Commit注解
@SpringBootTest
@Transactional
class UserServiceTest {
@Test
@Commit // 明確告訴 Spring 提交事務(wù),而不是回滾
void testUpdateAndCommit() {
userService.updateUserName(1L, "CommittedName");
// 測試結(jié)束后,修改會真正寫入數(shù)據(jù)庫
}
}
到此這篇關(guān)于Spring Boot的測試類中使用 @Transactional 注解的文章就介紹到這了,更多相關(guān)Spring Boot使用@Transactional 注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot事務(wù)注解@Transactional失效場景與解決方案
- 如何使用Spring boot的@Transactional進(jìn)行事務(wù)管理
- Springboot @Transactional大事務(wù)處理的幾點(diǎn)建議
- Springboot中@Transactional注解與異常處理機(jī)制方式
- SpringBoot?@Transactional事務(wù)不生效排查方式
- 解決SpringBoot中使用@Transactional注解遇到的問題
- springboot中使用@Transactional注解事物不生效的坑
- springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場景
相關(guān)文章
java實(shí)戰(zhàn)小技巧之優(yōu)雅的實(shí)現(xiàn)字符串拼接
字符串拼接是我們在Java代碼中比較經(jīng)常要做的事情,就是把多個字符串拼接到一起,這篇文章主要給大家介紹了關(guān)于java實(shí)戰(zhàn)小技巧之優(yōu)雅的實(shí)現(xiàn)字符串拼接的相關(guān)資料,需要的朋友可以參考下2021-08-08
淺談java中Math.random()與java.util.random()的區(qū)別
下面小編就為大家?guī)硪黄獪\談java中Math.random()與java.util.random()的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09
Java設(shè)計(jì)模式之策略模式詳細(xì)解析
這篇文章主要介紹了Java設(shè)計(jì)模式之策略模式詳細(xì)解析,策略模式中,定義算法族,分別封裝起來,讓他們之間可以相互轉(zhuǎn)化,此模式讓算法的變化獨(dú)立于使用算法的客戶,需要的朋友可以參考下2023-11-11
java實(shí)現(xiàn)voctor按指定方式排序示例分享
這篇文章主要介紹了java實(shí)現(xiàn)voctor按指定方式排序示例,需要的朋友可以參考下2014-03-03
Java多線程并發(fā)之線程池任務(wù)請求攔截測試實(shí)例
這篇文章主要介紹了Java多線程并發(fā)之線程池任務(wù)請求攔截測試實(shí)例,隊(duì)列中永遠(yuǎn)沒有線程被加入,即使線程池已滿,也不會導(dǎo)致被加入排隊(duì)隊(duì)列,實(shí)現(xiàn)了只有線程池存在空閑線程的時候才會接受新任務(wù)的需求,需要的朋友可以參考下2023-12-12
java 中Comparable與Comparator詳解與比較
這篇文章主要介紹了java 中Comparable與Comparator詳解與比較的相關(guān)資料,需要的朋友可以參考下2017-04-04
SpringBoot整合Drools的實(shí)現(xiàn)步驟
Drools是一個易于訪問企業(yè)策略、易于調(diào)整以及易于管理的開源業(yè)務(wù)規(guī)則引擎,符合業(yè)內(nèi)標(biāo)準(zhǔn),速度快、效率高。業(yè)務(wù)分析師或?qū)徍巳藛T可以利用它輕松查看業(yè)務(wù)規(guī)則,從而檢驗(yàn)是否已編碼的規(guī)則執(zhí)行所需的業(yè)務(wù)規(guī)則。本文將講述SpringBoot整合Drools的步驟2021-05-05

