代碼如下
以下代碼1不生效,2生效
解決方案
1,外層方法加注解,內層不加
2,不要拆分方法,把更新訂單操作放在帶事物的大方法中
3,拆方法(內部),注入自己,用代理對象調用
4,拆方法(單獨bean)
5,使用編程性事物
@Autowiredprivate TransactionTemplate transactionTemplate;
@Service
public class OrderService {public void updateOrder(Order order) {// 其他邏輯...this.updateOrderStatus(order); // 直接調用,事務不生效!}@Transactionalpublic void updateOrderStatus(Order order) {// 更新訂單狀態(期望事務生效,但實際不會)orderRepository.save(order);}
}
@Service
public class OrderService {@Transactional // 新增注解public void updateOrder(Order order) {// 其他邏輯...this.updateOrderStatus(order); // 直接調用}// 去掉了 @Transactional 注解public void updateOrderStatus(Order order) {orderRepository.save(order);}
}
代碼2的回復
關鍵問題
事務是否會生效?
updateOrderStatus
?是否會和?updateOrder
?在同一個事務中?
1.?事務是否生效?
? 事務會生效
因為?
updateOrder
?方法添加了?@Transactional
,且是通過外部調用(如?orderService.updateOrder()
)觸發的。Spring 的 AOP 代理會攔截該方法,開啟一個事務。
? 但有一個重要限制
updateOrderStatus
?是通過?this.updateOrderStatus()
?直接調用的(自調用),不會經過 Spring 代理。因此,
updateOrderStatus
?方法本身不會單獨開啟事務,但它的數據庫操作會繼承?updateOrder
?的事務。
2.?updateOrderStatus
?是否在同一個事務中?
? 是,在同一個事務中
雖然?
updateOrderStatus
?沒有自己的?@Transactional
?注解,但它的數據庫操作(如?orderRepository.save(order)
)會默認加入當前線程綁定的事務(即?updateOrder
?開啟的事務)。本質上,
updateOrder
?和?updateOrderStatus
?的數據庫操作是同一個事務的一部分。
3.?驗證事務行為
(1)測試代碼
java
@Transactional public void updateOrder(Order order) {orderRepository.save(order); // 操作1this.updateOrderStatus(order); // 操作2throw new RuntimeException("模擬異常"); // 觸發回滾 }public void updateOrderStatus(Order order) {orderRepository.save(order); // 操作3 }
(2)預期結果
如果事務生效,操作1、操作2、操作3都會回滾(因為它們在同一個事務中)。
如果事務不生效,數據會被正常保存。
4.?關鍵結論
場景 | 事務是否生效 | 是否同一事務 |
---|---|---|
updateOrder ?加?@Transactional | ? 生效 | ? 是 |
updateOrderStatus ?去注解 + 自調用 | 繼承外層事務 | ? 是 |
注意事項
自調用問題
雖然事務能生效,但直接?
this.updateOrderStatus()
?的調用方式不推薦,因為:如果未來?
updateOrderStatus
?需要獨立事務(如?REQUIRES_NEW
),這種寫法無法實現。代碼可維護性差(事務邊界不清晰)。
推薦改進
如果不需要獨立事務,直接合并邏輯到?
updateOrder
:java
@Transactional public void updateOrder(Order order) {// 其他邏輯...orderRepository.save(order); // 直接操作 }
如果需要拆分方法,用代理對象調用:
java
@Autowired private OrderService self; // 注入代理@Transactional public void updateOrder(Order order) {self.updateOrderStatus(order); // 通過代理調用 }
5.?最終答案
你的代碼中:
事務會生效,且?
updateOrder
?和?updateOrderStatus
?的操作在同一個事務中。但自調用(
this.xxx()
)是不推薦的寫法,未來可能埋坑。
改進建議:
java
@Service public class OrderService {@Transactionalpublic void updateOrder(Order order) {// 其他邏輯...orderRepository.save(order); // 直接操作,避免拆分} }
或(如需強制拆分):
java
@Service public class OrderService {@Autowiredprivate OrderService self; // 注入代理@Transactionalpublic void updateOrder(Order order) {self.updateOrderStatus(order); // 通過代理調用}@Transactional // 可按需調整傳播行為public void updateOrderStatus(Order order) {orderRepository.save(order);} }