3.1、方式一
经过上面分析,只需要代码中重新生成个 TransactionSynchronization 并加入到 TransactionSynchronizationManager 的 TransactionSynchronization 集合中即可,所以有了解决方案,如下:
private void writeStatisticsData(Long studentId) { if(TransactionSynchronizationManager.isActualTransactionActive()) { // 当前存在事务 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { executor.execute(() -> {Student student = studentService.findById(studentId); //........ }); }}); } else { // 当前不存在事务 executor.execute(() -> {Student student = studentService.findById(studentId); //........ }); } }
3.2、方式二
使用 @TransactionalEventListener 结合 Spring事件监听机制,该注解自从Spring4.2版本开始有的,如下:
// 事件 public class StudentEvent extends ApplicationEvent { public StudentEvent(Long studentId) { super(studentId); } } // 监听器 public class StudentEventListener{ @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) public void writeStatisticsData(StudentEvent studentEvent) { executor.execute(() -> { Student student = studentService.findById(studentEvent.getSource()); //........ }); } } @Service public class StudentService { // Spring4.2之后,ApplicationEventPublisher自动被注入到容器中,采用Autowired即可获取 @Autowired private ApplicationEventPublisher applicationEventPublisher; @Transactional public Long test() { // ...... // 插入记录 Long studentId = studentService.insert(student); // 发布事件 applicationEventPublisher.publishEvent(new StudentEvent(studentId)); // 插入学生地址记录 Long addressId = addressService.insert(address); return studentId; } }
原理分析
Spring Bean在加载配置文件时,会使用 AnnotationDrivenBeanDefinitionParser 来解析 annotation-driven 标签,如下:
public class TxNamespaceHandler extends NamespaceHandlerSupport { //...... @Override public void init() { registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser()); registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser()); } }
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { // 重点——将TransactionalEventListenerFactory加入到容器中 registerTransactionalEventListenerFactory(parserContext); String mode = element.getAttribute("mode"); if ("aspectj".equals(mode)) { // mode="aspectj" registerTransactionAspect(element, parserContext); } else { // mode="proxy" AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); } return null; } private void registerTransactionalEventListenerFactory(ParserContext parserContext) { RootBeanDefinition def = new RootBeanDefinition(); def.setBeanClass(TransactionalEventListenerFactory.class); parserContext.registerBeanComponent(new BeanComponentDefinition(def, TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)); } }
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered { //省略部分代码...... @Override public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) { return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method); } }
class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter { //省略部分代码...... @Override public void onApplicationEvent(ApplicationEvent event) { if (TransactionSynchronizationManager.isSynchronizationActive()) { // 事务存在时,生成TransactionSynchronization并加入到 TransactionSynchronizationManager的缓存集合中 TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event); TransactionSynchronizationManager.registerSynchronization(transactionSynchronization); } else if (this.annotation.fallbackExecution()) { //....... } processEvent(event); } else { // 当前不存在事务什么也不做 } }
上述 @TransactionalEventListener 本质上是一个 @EventListener,TransactionalEventListenerFactory类会将每一个扫描到的方法有TransactionalEventListener注解包装成ApplicationListenerMethodTransactionalAdapter对象,通过ApplicationListenerMethodTransactionalAdapter的onApplicationEvent方法可以看到若当前存在事务,就会生成TransactionSynchronization并加入到 TransactionSynchronizationManager的缓存ThreadLocal集合中,剩余流程同上述分析。(使用 @TransactionalEventListener 结合 Spring事件监听机制,并使用到异步方式感觉有点别扭,这里是为了说明问题)。