在某些特定的業務場景下,我們可能需要在事務成功提交之后,再做某些操作,而不能將這些操作放在事務代碼中,事務還未提交就已經執行了,那這種情況之下,spring提供的TransactionalEventListener就會派上用場了。
使用demo
@Service @Slf4j public class UserService implements ApplicationEventPublisherAware { private ApplicationEventPublisher eventPublisher; @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void demo() { User user = new User("zhangsan", "M", 30); // 發布事件,等事務commit之后執行 eventPublisher.publishEvent(new DemoEvent(user)); jdbcTemplate.update( "insert into t_user (`name`, `sex`, `age`) values (?, ?, ?)", user.getName(), user.getSex(), user.getAge()); log.info("事務中的業務邏輯執行完畢"); } @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.eventPublisher = applicationEventPublisher; } } public class DemoEvent extends ApplicationEvent { public DemoEvent(Object source) { super(source); } } @Component @Slf4j public class DemoListener { @TransactionalEventListener( phase = TransactionPhase.AFTER_COMMIT, classes = DemoEvent.class) public void onEvent(DemoEvent demoEvent) { log.info("收到事件,事件源是:{}", demoEvent.getSource()); // todo 事務提交后的業務處理 } }
1. 調用DemoService的demo方法時,控制台輸出
事務中的業務邏輯執行完畢
收到事件,事件源是:User(name=zhangsan, sex=M, age=30)
2. 如果業務代碼中拋出異常,事務回滾,則監聽器中的邏輯將不會執行
@Transactional public void demo() { User user = new User("zhangsan", "M", 30); // 發布事件,等事務commit之后執行 eventPublisher.publishEvent(new DemoEvent(user)); jdbcTemplate.update( "insert into t_user (`name`, `sex`, `age`) values (?, ?, ?)", user.getName(), user.getSex(), user.getAge()); log.info("事務中的業務邏輯執行完畢"); // 模擬業務異常 throw new RuntimeException(); }
再次調用DemoService的demo方法時,控制台只會輸出
事務中的業務邏輯執行完畢