使用?TransactionTemplate
等類和 API 手動管理事務,控制事務的新建、提交、回滾等過程
方式一:使用 TransactionTemplate
(推薦方式)
@Service
public class OrderService {private final TransactionTemplate transactionTemplate;private final OrderRepository orderRepository;private final InventoryRepository inventoryRepository;public OrderService(PlatformTransactionManager txManager,OrderRepository orderRepository,InventoryRepository inventoryRepository) {this.transactionTemplate = new TransactionTemplate(txManager);this.orderRepository = orderRepository;this.inventoryRepository = inventoryRepository;}public void createOrder(Order order) {transactionTemplate.execute(status -> {try {// 操作1: 保存訂單orderRepository.save(order);// 操作2: 扣減庫存inventoryRepository.deductStock(order.getProductId(), order.getQuantity());return "SUCCESS";} catch (Exception e) {status.setRollbackOnly(); // 標記回滾throw new RuntimeException("Transaction rolled back", e);}});}
}
方式二:使用 PlatformTransactionManager
(精細控制)
@Service
public class PaymentService {private final PlatformTransactionManager txManager;private final PaymentRepository paymentRepository;public PaymentService(PlatformTransactionManager txManager, PaymentRepository paymentRepository) {this.txManager = txManager;this.paymentRepository = paymentRepository;}public void processPayment(Payment payment) {// 定義事務屬性(傳播行為、隔離級別)DefaultTransactionDefinition definition = new DefaultTransactionDefinition();definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);TransactionStatus status = txManager.getTransaction(definition);try {// 業務操作paymentRepository.save(payment);// 模擬外部服務調用(若失敗需回滾)if (!externalPaymentGateway.charge(payment)) {throw new RuntimeException("Payment failed");}txManager.commit(status);} catch (Exception e) {txManager.rollback(status);throw e;}}
}
為什么不建議用聲明式事務?
1)粒度不可控,最低是方法級別,容易造成大事務
2)使用不當,可能造成事務回滾不完全造成業務故障,如方法中調用了第三方接口,接口調用不能回滾
3)失效場景眾多,一不小心就會造成事務失效