Spring Event 事件中的事务控制

原创
2017/04/20 17:11
阅读数 1.5W

Spring Event 可以简单实现业务解耦,从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener

    @EventListener(condition = "#event.shouldSendMsg")
    public void afterRegisterSendMail(MessageEvent event) {
         mailService.send(event.getUser().getEmail(),"register successful");
    }

事务绑定事件

标准的事件模型在一些业务上能很好的满足需求,例如异步化处理,不干扰主线程执行等,不论事务被提交或回滚,都能正常执行.但是如果我们只是希望事务被提交后,再执行事件呢?

例如,用户注册成功后添加一个发送邮件的事件,或者推送消息,或者短信,这时候需要保存数据库后,再进行这些操作.但是万一事务提交失败数据库事务会回滚,这时候如果用户收到邮件,那可惨淡了!

在Spring事务管理中, 事务是配置注解声明的 (@Transactional) 提交操作将在方法结束后执行. 提交是自动自行的(transaction.commit()). 以下是一些解决方式:

解决方案1(<Spring 4.2):

@EventListener
public void afterRegisterSendMail(MessageEvent event) {
    // Spring 4.2 之前
 
    TransactionSynchronizationManager.registerSynchronization(
            new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    internalSendMailNotification(event);
                }
            });
}

上面的代码将在事务提交后执行.如果在非事务context中将抛出java.lang.IllegalStateException: Transaction synchronization is not active,

	@EventListener
		public void afterRegisterSendMail(MessageEvent event) {
		    // Spring 4.2 之前
		 
		    if (TransactionSynchronizationManager.isActualTransactionActive()) {
		 
		        TransactionSynchronizationManager.registerSynchronization(
		                new TransactionSynchronizationAdapter() {
		                    @Override
		                    public void afterCommit() {
		                    	mailService.send(event);
		                    }
		                });
		    } else {
		        mailService.send(event);
		    }
		}

这样无论是否有事务都能兼容啦. 下面介绍Spring 4.2以后的简化处理:

解决方案2(Spring 4.2 +)

Spring 4.2除了EventListener之外,额外提供了新的注解TransactionalEventListener

	    @TransactionalEventListener
		public void afterRegisterSendMail(MessageEvent event) {
			mailService.send(event);
		}

这个注解的强大之处在于可一直控制事务的 before/after commit, after rollback ,after completion (commit或 rollback). 默认情况下,在事务中的Event将会被执行,其他情况不触发.

在非事务context下,如果也想执行,启用参数:fallbackExecution=true,

	    @TransactionalEventListener(fallbackExecution = true)
		public void afterRegisterSendMail(MessageEvent event) {
			mailService.send(event);
		}

 

https://my.oschina.net/osgit/blog/883823

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部