@Transactional前文
propagation
在 Spring 的 @Transactional 註解中,propagation 屬性控制著事務的傳播行為,決定了當一個方法在事務上下文中被調用時該如何處理事務。
Propagation.REQUIRED
含義:
使用場景:
適用於大多數情況,確保方法在事務中執行,維護資料一致性。
範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Service public class OrderService {
@Autowired private InventoryService inventoryService;
@Autowired private PaymentService paymentService;
@Transactional(propagation = Propagation.REQUIRED) public void placeOrder(Order order) { inventoryService.reduceStock(order.getProductId(), order.getQuantity()); paymentService.processPayment(order.getPaymentInfo()); orderRepository.save(order); } }
|
placeOrder 方法需要確保所有操作在同一事務中執行,避免部分操作成功、部分失敗的情況。
Propagation.REQUIRES_NEW
含義:
使用場景:
需要方法在獨立的事務中執行,與外部事務隔離。
範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Service public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW) public void logAudit(AuditRecord record) { auditRepository.save(record); } } @Service public class UserService {
@Autowired private AuditService auditService;
@Transactional(propagation = Propagation.REQUIRED) public void updateUser(User user) { userRepository.save(user); auditService.logAudit(new AuditRecord("User updated", user.getId())); } }
|
logAudit 方法在一個新事務中執行,確保審計記錄總是被保存,即使 updateUser 方法的事務回滾。
Propagation.SUPPORTS
含義:
使用場景:
方法不需要強制事務支持,可有可無。
範例:
1 2 3 4 5 6 7 8 9
| @Service public class ProductService {
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true) public Product getProductById(Long id) { return productRepository.findById(id).orElse(null); } }
|
getProductById 方法主要執行查詢操作,在有事務時參與事務,無事務時以非事務方式執行。
Propagation.NOT_SUPPORTED
含義:
使用場景:
避免方法在事務中執行,防止長時間運行導致事務佔用資源。
範例:
1 2 3 4 5 6 7 8 9
| @Service public class ReportService {
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void generateReport() { reportGenerator.generate(); } }
|
generateReport 方法執行時間較長,不需要事務支持,避免長時間佔用事務資源。
Propagation.NESTED
含義:
使用場景:
需要在一個大事務中,對某部分操作單獨回滾,而不影響整體事務。
範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @Service public class PaymentService {
@Transactional(propagation = Propagation.NESTED) public void processPayment(Payment payment) { paymentRepository.save(payment); if (payment.getAmount() > 1000) { throw new RuntimeException("付款金額過大"); } } }
@Service public class OrderService {
@Autowired private PaymentService paymentService;
@Transactional(propagation = Propagation.REQUIRED) public void placeOrder(Order order) { orderRepository.save(order); try { paymentService.processPayment(order.getPayment()); } catch (Exception e) { System.out.println("付款失敗:" + e.getMessage()); } } }
|
Propagation.MANDATORY
含義:
必須存在事務:方法必須在事務中執行。
拋出異常:如果當前沒有事務,將拋出異常。
使用場景:
方法需要在事務上下文中執行,否則無法保證資料一致性。
範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Service public class NotificationService {
@Transactional(propagation = Propagation.MANDATORY) public void sendNotification(Notification notification) { notificationRepository.save(notification); } }
@Service public class OrderService {
@Autowired private NotificationService notificationService;
@Transactional(propagation = Propagation.REQUIRED) public void completeOrder(Order order) { orderRepository.save(order); notificationService.sendNotification(new Notification("Order completed", order.getUserId())); } }
|
Propagation.NEVER
含義:
禁止事務執行:方法必須在非事務環境中執行。
拋出異常:如果當前存在事務,將拋出異常。
使用場景:
嚴格要求方法不能在事務中執行。
範例:
1 2 3 4 5 6 7 8 9
| @Service public class CacheService {
@Transactional(propagation = Propagation.NEVER) public void refreshCache() { cacheManager.refreshAll(); } }
|
refreshCache 方法不應該在事務中執行,以免影響快取一致性。
Propagation.REQUIRED V.S. Propagation.MANDATORY
Propagation.REQUIRED
適用情況:
範例:
1 2 3 4 5
| @Transactional(propagation = Propagation.REQUIRED) public void updateAccount(Account account) { accountRepository.save(account); }
|
- 無論調用
updateAccount 方法時是否存在事務,該方法都能保證在事務中執行。
Propagation.MANDATORY
適用情況:
範例:
1 2 3 4 5 6 7
| @Transactional(propagation = Propagation.MANDATORY) public void validateTransaction(Transaction tx) { if (!isValid(tx)) { throw new InvalidTransactionException(); } }
|