Spring中明明插入了数据,为什么事件监听器EventListener却读不到?

4d4bb2ab8f2b99a1658c4f63c38cc28e.png

若有收获,请记得分享和转发哦

一、问题描述

平时我们在完成某些数据的入库后,发布了一个事件,此时使用的是 @EventListener,然后在这个事件中,又去对刚才入库的数据进行查询,从而完成后续的操作。例如(数据入库=>对入库数据进行查询审核),这时候会发现,查询不到刚才入库的数据,这是因为事务还没提交完成,在同一个事务当中,查询不到才存入的数据,那么就引出了下面的解决方式。

为了解决上述问题,Spring为我们提供了两种方式:

  1. @TransactionalEventListener注解。

  2. 事务同步管理器TransactionSynchronizationManager

以便我们可以在事务提交后再触发某一事件来进行其他操作。

二、使用场景

在项目当中,我们有时候需要在执行数据库操作之后,发送消息或事件来异步调用其他组件执行相应的操作,例如:

  1. 数据完成导入之后,发布审核事件,对入库的数据进行审核。

  2. 用户在完成注册后发送激活码。

  3. 配置修改后,发送更新配置的事件。

三、@TransactionalEventListener详解

我们可以从命名上直接看出,它就是个 EventListener,在Spring4.2+,有一种叫做 @TransactionEventListener的方式,能够实现在控制事务的同时,完成对对事件的处理。

我们知道,Spring的事件监听机制(发布订阅模型)实际上并不是异步的(默认情况下),而是同步的来将代码进行解耦。而 @TransactionEventListener仍是通过这种方式,但是加入了回调的方式来解决,这样就能够在事务进行Commited,Rollback…等时候才去进行Event的处理,来达到事务同步的目的。

// @since 4.2 注解的方式提供的相对较晚,其实API的方式在第一个版本就已经提供了。
// 值得注意的是,在这个注解上面有一个注解:`@EventListener`,所以表明其实这个注解也是个事件监听器。 
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EventListener //有类似于注解继承的效果
public @interface TransactionalEventListener {
    // 这个注解取值有:BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK、AFTER_COMPLETION
    // 各个值都代表什么意思表达什么功能,非常清晰,下面解释了对应的枚举类~
    // 需要注意的是:AFTER_COMMIT + AFTER_COMPLETION是可以同时生效的
    // AFTER_ROLLBACK + AFTER_COMPLETION是可以同时生效的
    TransactionPhase phase() default TransactionPhase.AFTER_COMMIT;
    
    // 表明若没有事务的时候,对应的event是否需要执行,默认值为false表示,没事务就不执行了。
    boolean fallbackExecution() default false;

    // 这里巧妙的用到了@AliasFor的能力,放到了@EventListener身上
    // 注意:一般建议都需要指定此值,否则默认可以处理所有类型的事件,范围太广了。
    @AliasFor(annotation = EventListener.class, attribute = "classes")
    Class[] value() default {};
    @AliasFor(annotation = EventListener.class, attribute = "classes")
    Class[] classes() default {};

    String condition() default "";
}
public enum TransactionPhase {
   // 指定目标方法在事务commit之前执行
   BEFORE_COMMIT,
   // 指定目标方法在事务commit之后执行
   AFTER_COMMIT,
   // 指定目标方法在事务rollback之后执行
   AFTER_ROLLBACK,
   // 指定目标方法在事务完成时执行,这里的完成是指无论事务是成功提交还是事务回滚了
   AFTER_COMPLETION
}

四、代码示例

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第1张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第2张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第3张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第4张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第5张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第6张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第7张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第8张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第9张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第10张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第11张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第12张图片

Spring中明明插入了数据,为什么事件监听器EventListener却读不到?_第13张图片

六、小结

对于事务事件的处理,总结而言,就是为每个事务事件监听方法创建了一个 TransactionSynchronizationEventAdapter对象,通过该对象在发布事务事件的时候,会在当前线程中注册该对象,这样就可以保证每个线程每个监听器中只会对应一个 TransactionSynchronizationEventAdapter对象。在Spring进行事务事件的时候会调用该对象对应的监听方法,从而达到对事务事件进行监听的目的。

bd95894f0da3cabbea1deda9bb8e0da5.png

烧脑?放松一下,听下音乐吧

9c290254a3c520e14f269ead31094320.png

点击下方

你可能感兴趣的:(java,spring,python,数据库,vue)