Cả hai lắng nghe ApplicationEvent, nhưng khác nhau ở thời điểm chạy so với transaction.
@EventListener — chạy ngay lập tức khi event được publish, trong cùng transaction:
@EventListener
void onOrderPlaced(OrderPlacedEvent event) {
// Chạy TRONG transaction của placeOrder()
// Nếu phương thức này throw → transaction rollback toàn bộ
emailService.sendConfirmation(event.getOrderId());
}@TransactionalEventListener — chạy sau khi transaction commit thành công:
@Component
class OrderEmailListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
void onOrderPlaced(OrderPlacedEvent event) {
// Chỉ chạy khi order đã được persist vào DB
// Nếu transaction rollback → event bị bỏ qua hoàn toàn
emailService.sendConfirmation(event.getOrderId());
}
}
// Publisher
@Service
class OrderService {
@Transactional
void placeOrder(Order order) {
orderRepo.save(order);
// Event publish ở đây, nhưng listener chạy SAU KHI commit
events.publishEvent(new OrderPlacedEvent(order.getId()));
}
}Phases:
- AFTER_COMMIT (default) — sau commit thành công.
- AFTER_ROLLBACK — sau rollback.
- AFTER_COMPLETION — sau cả commit lẫn rollback.
- BEFORE_COMMIT — trước commit.
Vì sao quan trọng: gửi email/notification chỉ nên xảy ra khi data đã thực sự được lưu. Dùng @EventListener để gửi email trước commit → order có thể rollback nhưng email đã gửi rồi.
Both listen to ApplicationEvent, but differ in when they run relative to a transaction.
@EventListener — runs immediately when the event is published, inside the same transaction:
@EventListener
void onOrderPlaced(OrderPlacedEvent event) {
// Runs INSIDE placeOrder()'s transaction
// If this method throws → entire transaction rolls back
emailService.sendConfirmation(event.getOrderId());
}@TransactionalEventListener — runs after the transaction commits successfully:
@Component
class OrderEmailListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
void onOrderPlaced(OrderPlacedEvent event) {
// Only runs when the order has been persisted to DB
// If the transaction rolls back → event is discarded entirely
emailService.sendConfirmation(event.getOrderId());
}
}
// Publisher
@Service
class OrderService {
@Transactional
void placeOrder(Order order) {
orderRepo.save(order);
// Event is published here, but listener runs AFTER commit
events.publishEvent(new OrderPlacedEvent(order.getId()));
}
}Phases:
- AFTER_COMMIT (default) — after successful commit.
- AFTER_ROLLBACK — after rollback.
- AFTER_COMPLETION — after either commit or rollback.
- BEFORE_COMMIT — before commit.
Why it matters: emails and notifications should only fire when data is actually saved. Using @EventListener to send an email before commit → the order could roll back but the email is already sent.