如何使用Spring boot的@Transactional進行事務管理
在 Spring Boot 中,@Transactional 是用于聲明式事務管理的關鍵注解。它基于 Spring 的 AOP(面向切面編程)實現(xiàn),可以簡化數(shù)據(jù)庫事務的管理。
一、前置條件
- 依賴引入:確保項目中包含
spring-boot-starter-data-jpa或spring-boot-starter-jdbc - 啟用事務管理:Spring Boot 默認自動配置事務管理器(如
DataSourceTransactionManager),無需手動啟用。
二、基本用法
1. 在方法上添加注解
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 其他數(shù)據(jù)庫操作
}
}2. 在類上添加注解
@Service
@Transactional
public class UserService {
// 類中所有 public 方法都會應用事務
}三、核心配置參數(shù)
1. 傳播行為(Propagation)
控制事務的邊界,默認為 Propagation.REQUIRED。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser(User user) {
// 始終開啟新事務
}常見選項:
REQUIRED(默認):如果當前存在事務,則加入;否則新建REQUIRES_NEW:始終新建事務,掛起當前事務(如有)SUPPORTS:如果當前存在事務,則加入;否則非事務運行NOT_SUPPORTED:非事務運行,掛起當前事務(如有)MANDATORY:必須在事務中調(diào)用,否則拋出異常NEVER:必須在非事務中調(diào)用,否則拋出異常
2. 隔離級別(Isolation)
控制事務的隔離性,默認為 Isolation.DEFAULT(使用數(shù)據(jù)庫默認)。
@Transactional(isolation = Isolation.SERIALIZABLE)
public void sensitiveOperation() {
// 最高隔離級別
}3. 超時時間(Timeout)
事務超時時間(秒),默認-1(使用數(shù)據(jù)庫默認)。
@Transactional(timeout = 30)
public void longRunningProcess() {
// 超過30秒將回滾
}4. 只讀模式(readOnly)
優(yōu)化只讀操作,默認為 false。
@Transactional(readOnly = true)
public List<User> findAllUsers() {
return userRepository.findAll();
}5. 回滾規(guī)則(rollbackFor/noRollbackFor)
指定觸發(fā)回滾的異常類型:
@Transactional(rollbackFor = CustomException.class)
public void process() throws CustomException {
// 拋出 CustomException 時回滾
}四、關鍵注意事項
1. 方法可見性
必須為 public:由于 Spring AOP 的實現(xiàn)機制,非 public 方法上的 @Transactional 無效
2. 自調(diào)用問題
同類中的方法互相調(diào)用時,事務不會生效(繞過代理對象)
// 錯誤示例
public void methodA() {
methodB(); // 事務不生效
}
@Transactional
public void methodB() { ... }3. 異常處理
- 默認回滾條件:拋出
RuntimeException或Error - 檢查型異常(Checked Exception)默認不會觸發(fā)回滾
// 處理檢查型異常
@Transactional(rollbackFor = IOException.class)
public void fileOperation() throws IOException {
// ...
}4. 多數(shù)據(jù)源事務
需配置多個事務管理器,并通過 @Transactional(value = "specificTransactionManager") 指定
五、調(diào)試技巧
啟用調(diào)試日志:
logging.level.org.springframework.transaction.interceptor=TRACE logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
檢查代理對象:
System.out.println(userService.getClass().getName()); // 輸出應為代理類:com.sun.proxy.$ProxyXX 或 ...$$EnhancerBySpringCGLIB$$...
六、最佳實踐
- 服務層使用:在 Service 層而非 Controller 層使用事務
- 保持短事務:避免在事務中包含遠程調(diào)用、文件IO等耗時操作
- 精確回滾規(guī)則:明確指定
rollbackFor而非依賴默認行為 - 結合 JPA 使用:
@Transactional
public void updateUserEmail(Long userId, String email) {
User user = userRepository.findById(userId).orElseThrow();
user.setEmail(email); // 自動臟檢查,事務提交時更新
}七、完整示例
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryService inventoryService;
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 30,
rollbackFor = {InsufficientStockException.class, PaymentFailedException.class}
)
public void placeOrder(Order order) {
inventoryService.reduceStock(order.getItems()); // 可能拋出 InsufficientStockException
orderRepository.save(order);
processPayment(order); // 可能拋出 PaymentFailedException
}
private void processPayment(Order order) {
// 支付邏輯
}
}八、適用于關系型數(shù)據(jù)庫
@Transactional 的使用與數(shù)據(jù)庫層有直接關系,但它的事務管理機制是基于數(shù)據(jù)庫事務的。如果 Service 層方法使用了 Elasticsearch 客戶端讀寫 Elasticsearch,那么 @Transactional 的行為會受到影響。
1.@Transactional 的適用范圍
@Transactional是 Spring 提供的事務管理機制,主要用于管理數(shù)據(jù)庫事務。- 它依賴于底層的事務管理器(如
DataSourceTransactionManager),而這些事務管理器通常是與關系型數(shù)據(jù)庫(如 MySQL、PostgreSQL)交互的。
數(shù)據(jù)庫事務:@Transactional 可以確保數(shù)據(jù)庫操作的原子性、一致性、隔離性和持久性(ACID)。非數(shù)據(jù)庫操作:對于非數(shù)據(jù)庫操作(如 Elasticsearch、Redis、文件系統(tǒng)等),@Transactional 無法直接管理其事務。
2.Elasticsearch 與 @Transactional 的關系
Elasticsearch 是一個分布式搜索引擎,它本身不支持傳統(tǒng)意義上的事務(ACID)。因此,@Transactional 對 Elasticsearch 的操作沒有直接的事務管理能力。
(1)場景分析
假設我們的 Service 方法同時操作了數(shù)據(jù)庫和 Elasticsearch:
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 數(shù)據(jù)庫操作
@Autowired
private ElasticsearchClient elasticsearchClient; // Elasticsearch 操作
@Transactional
public void createUser(User user) {
// 操作數(shù)據(jù)庫
userRepository.save(user);
// 操作 Elasticsearch
IndexRequest request = new IndexRequest("users")
.id(user.getId().toString())
.source("name", user.getName(), "email", user.getEmail());
elasticsearchClient.index(request, RequestOptions.DEFAULT);
}
}(2)可能出現(xiàn)的問題
- 數(shù)據(jù)庫事務回滾,Elasticsearch 操作不回滾:
- 如果 userRepository.save(user) 成功,但后續(xù) Elasticsearch 操作失敗,數(shù)據(jù)庫事務會回滾(因為 @Transactional 生效),但 Elasticsearch 的數(shù)據(jù)已經(jīng)寫入,無法回滾。
- 數(shù)據(jù)庫事務提交,Elasticsearch 操作失?。?/li>
- 如果數(shù)據(jù)庫操作成功,但 Elasticsearch 操作失敗,數(shù)據(jù)庫事務已經(jīng)提交,而 Elasticsearch 數(shù)據(jù)未更新,導致數(shù)據(jù)不一致。
3.如何解決 Elasticsearch 與數(shù)據(jù)庫的事務一致性問題
由于 Elasticsearch 不支持事務,因此需要采用其他機制來保證數(shù)據(jù)一致性。
(1)手動補償機制 在 Elasticsearch 操作失敗時,手動回滾數(shù)據(jù)庫操作。
示例:
@Transactional
public void createUser(User user) {
try {
userRepository.save(user); // 數(shù)據(jù)庫操作
IndexRequest request = new IndexRequest("users")
.id(user.getId().toString())
.source("name", user.getName(), "email", user.getEmail());
elasticsearchClient.index(request, RequestOptions.DEFAULT); // Elasticsearch 操作
} catch (Exception e) {
// Elasticsearch 操作失敗,手動回滾數(shù)據(jù)庫
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw e;
}
}(2)消息隊列(最終一致性)
- 將 Elasticsearch 操作異步化,通過消息隊列(如 Kafka、RabbitMQ)實現(xiàn)最終一致性。
- 示例:
數(shù)據(jù)庫操作完成后,發(fā)送消息到隊列。
消費者從隊列中讀取消息并更新 Elasticsearch。
(3)兩階段提交(2PC)
- 使用分布式事務管理器(如 Seata)實現(xiàn)數(shù)據(jù)庫和 Elasticsearch 的分布式事務。
- 這種方法復雜度較高,通常不推薦用于 Elasticsearch。
(4)本地消息表
- 在數(shù)據(jù)庫中創(chuàng)建一張消息表,記錄需要同步到 Elasticsearch 的數(shù)據(jù)。
- 通過定時任務或事件監(jiān)聽器將數(shù)據(jù)同步到 Elasticsearch。
總結
@Transactional只對數(shù)據(jù)庫事務有效:它無法管理 Elasticsearch 等非關系型數(shù)據(jù)存儲的事務。- Elasticsearch 操作與數(shù)據(jù)庫事務的一致性:需要通過補償機制、消息隊列等方式實現(xiàn)。
- 設計建議: 盡量避免在同一個事務中混合數(shù)據(jù)庫和 Elasticsearch 操作。
- 采用異步化或最終一致性方案來保證數(shù)據(jù)一致性。
如果你有更多具體的業(yè)務場景,可以進一步討論如何設計解決方案!
到此這篇關于使用Spring boot的@Transactional進行事務管理的文章就介紹到這了,更多相關Spring boot @Transactional事務管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
MyBatis-Plus聯(lián)表查詢以及分頁代碼實例
在開發(fā)中遇到了一個問題,需要進行聯(lián)表查詢并進行分頁,因為不想自己來寫分頁,所以還是依靠MybatisPlus來實現(xiàn)想要的功能,下面這篇文章主要給大家介紹了關于MyBatis-Plus聯(lián)表查詢以及分頁的相關資料,需要的朋友可以參考下2023-06-06
SpringCloud的網(wǎng)關Zuul和Gateway詳解
SpringCloudZuul和SpringCloudGateway都是用于構建微服務架構中的API網(wǎng)關的組件,但SpringCloudGateway在性能、功能特性和生態(tài)支持等方面有一些優(yōu)勢,因此推薦使用SpringCloudGateway作為首選2025-02-02
Java生產(chǎn)者和消費者實現(xiàn)等待喚醒機制
本文主要介紹了Java生產(chǎn)者和消費者實現(xiàn)等待喚醒機制,通過synchronized、wait()和notifyAll()實現(xiàn)線程間的安全協(xié)作,具有一定的參考價值,感興趣的可以了解一下2025-06-06
Java中的logback標記日志過濾器MarkerFilter詳解
這篇文章主要介紹了Java中的logback標記日志過濾器MarkerFilter詳解,在logback-classic中存在一個全局過濾器TurboFilter,TurboFilter是與LoggerContext綁定,會在會在其它過濾器之前執(zhí)行,需要的朋友可以參考下2023-11-11
Java?Jenkins、Dockers和Kubernetes有什么區(qū)別詳細總結
這篇文章主要介紹了Java?Jenkins、Dockers和Kubernetes有什么區(qū)別的相關資料,Jenkins、Docker和Kubernetes分別在自動化流程、容器化封裝與容器編排三個關鍵層面發(fā)揮著重要作用,需要的朋友可以參考下2025-11-11

