前言

  • 在某些特定的业务场景下,我们可能需要在事务成功提交之后,再做某些操作,比如操作成功后发送消息到 MQ 中。
  • 不能将这些操作放在事务代码中,会导致事务还未提交就已经执行了,我们需要一种事务提交成功后操作的方法。
  • 那这种情况之下,spring 提供的 TransactionalEventListener 就会派上用场了。
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
34
@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);
}
}
1

1
2
3
4
5
6
7
8
9
10
@Component
@Slf4j
public class DemoListener {
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT,
classes = DemoEvent.class)
public void onEvent(DemoEvent demoEvent) {
log.info("收到事件,事件源是:{}", demoEvent.getSource());
// todo 事务提交后的业务处理
}

}
调用 DemoService 的 demo 方法时,控制台输出
事务中的业务逻辑执行完毕

收到事件,事件源是:User(name=zhangsan, sex=M, age=30)

  1. 如果业务代码中抛出异常,事务回滚,则监听器中的逻辑将不会执行

    @Transactional
    public void demo() {

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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 方法时,控制台只会输出

事务中的业务逻辑执行完毕

使用非常简单,记录一下