需要在事务提交后执行的操作-springBoot版。

该博客介绍了在SpringBoot中如何实现在事务提交后执行特定操作,如发送短信和邮件。通过创建一个`TransactionAfterCommitExecutor`类,它实现了`Executor`和`TransactionSynchronization`接口,将任务存入线程局部变量,并在事务提交后从线程池中异步执行。此外,还展示了`TransactionThreadFactory`用于创建线程,以及`UserService`中的`register`方法如何使用这个执行器来处理用户注册后的通知任务。

需要在事务提交后执行的操作-springBoot版。

需要在事务提交后执行的操作-springBoot版。

应用场景, 注册成功后需要将发送 短信、邮件 将用户推送至不同平台

import com.example.springbootevent.factory.TransactionThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author: Zoudx
 * @Date: 2022/7/18 16:05
 * @Description: 事务结束后需执行操作
 */
@Component
public class TransactionAfterCommitExecutor implements Executor, TransactionSynchronization {

    private static final Logger logger = LoggerFactory.getLogger(TransactionAfterCommitExecutor.class);

    private static final ThreadLocal<List<Runnable>> RUNNABLES = new ThreadLocal<>();

    private final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue(100), new TransactionThreadFactory("TransactionAfterCommitExecutor"), new ThreadPoolExecutor.AbortPolicy());


    @Override
    public void execute(Runnable runnable) {
        logger.info("{}:Execute after transaction ends" , Thread.currentThread().getName());
        // 不存在事务, 直接执行
        if (!TransactionSynchronizationManager.isActualTransactionActive()) {
            runnable.run();
            return;
        }
        // 存在事务,存入线程变量中, 待事务提交后执行
        List<Runnable> runnables = RUNNABLES.get();
        if (runnables == null) {
            runnables = new ArrayList<>();
        }
        TransactionSynchronizationManager.registerSynchronization(this);
        runnables.add(runnable);
        RUNNABLES.set(runnables);
    }

    @Override
    public void afterCommit() {
        // 事务结束后执行
        List<Runnable> runnables = RUNNABLES.get();
        for (Runnable runnable : runnables) {
            logger.info("execute runnable");
            try {
                THREAD_POOL_EXECUTOR.execute(runnable);
            } catch (Exception e) {
                logger.error("Failed to execute runnable:{}", runnable);
            }
        }
    }


    @Override
    public void afterCompletion(int status) {
        logger.info("Transaction completed with status {}", status == STATUS_COMMITTED ? "COMMITTED" : "ROLLED_BACK");
        RUNNABLES.remove();
    }
}

TransactionThreadFactory

/**
 * @author: Zoudx
 * @Date: 2022/7/19 10:05
 * @Description:
 */
public class TransactionThreadFactory implements ThreadFactory {

    private static final Logger logger = LoggerFactory.getLogger(TransactionAfterCommitExecutor.class);
    /**
     * 线程编号
     */
    private final AtomicInteger count = new AtomicInteger(0);

    /**
     * 线程前缀
     */
    private String threadPre;

    public TransactionThreadFactory(String threadName) {
        this.threadPre = threadName;
    }


    @Override
    public Thread newThread(Runnable r) {
        int increment = count.getAndIncrement();
        Thread t = new Thread(r);
        t.setName(threadPre + "-" + increment);
        logger.info("create {} thread", increment);
        return t;
    }
}

Service

/**
 * @author: Zoudx
 * @Date: 2022/7/15 11:40
 * @Description: 用户业务处理类
 */
@Service
@AllArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    private final TransactionAfterCommitExecutor afterCommitExecutor;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(User user) {
        // 注册
        logger.info("用户注册,参数正常:{}", JSON.toJSON(user));
        try {
            // 保存用户
            this.save(user);
            // 注册结束后需要处理操作
            afterCommitExecutor.execute(() -> ApplicationContextUtil.publishEvent(new UserEvent(user, user.getId())));
        } catch (Exception e) {
            logger.error("Create user Failed");
        }

    }
}

ApplicationContextUtil用户获取容器中的bean以及发布事件

/**
 * @author: Zoudx
 * @Date: 2022/7/15 11:42
 * @Description:
 */
@Component
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> tClass) {
        return applicationContext.getBean(tClass);
    }

    public static <T> T getBean(String beanName) {
        return (T) applicationContext.getBean(beanName);
    }

    public static void publishEvent(Object object) {
        applicationContext.publishEvent(object);
    }


}
<think>我们被要求回答:在Spring Boot中如何实现事务提交后执行其他操作 根据引用的内容,特别是引用[3]和引用[4],我们可以找到两种方法: 方法1:使用TransactionSynchronizationManager注册一个事务同步回调(引用[3]) 方法2:使用一个自定义的TransactionAfterCommitExecutor(引用[4]) 下面我们将详细说明这两种方法。 方法1:使用TransactionSynchronizationManager 步骤: 1. 检查当前是否存在活动的事务(TransactionSynchronizationManager.isActualTransactionActive()) 2. 如果存在,注册一个TransactionSynchronizationAdapter,并重写其afterCommit方法,在该方法中执行需要在事务提交后执行操作。 示例代码(参考引用[3]): if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { // 事务提交后执行操作 log.info("当前事务提交,执行业务逻辑"); // do something } }); } else { // 没有事务,直接执行 log.info("当前无事务,直接执行业务逻辑"); // do something } 注意:TransactionSynchronizationAdapter是一个抽象类,通常我们只重写需要的方法(如afterCommit)。另外,在Spring 5.0以后,可以使用TransactionSynchronization接口并直接使用default方法,但使用适配器类仍然是一种常见做法。 方法2:使用自定义的TransactionAfterCommitExecutor(参考引用[4]) 这种方法封装了事务提交后的执行逻辑,通过一个执行器来执行。在引用[4]中,使用了afterCommitExecutor.execute(...)来执行一个在事务提交后的操作。 步骤: 1. 创建一个实现了TransactionAfterCommitExecutor的Bean,它通常使用TransactionSynchronizationManager来注册回调。 2. 在需要的地方注入该Bean,并在事务方法中使用它。 引用[4]中的示例: 在Service中注入了TransactionAfterCommitExecutor,然后在事务方法中调用: afterCommitExecutor.execute(() -> ApplicationContextUtil.publishEvent(new UserEvent(user, user.getId()))); 我们可以自己实现一个简单的TransactionAfterCommitExecutor: @Component public class TransactionAfterCommitExecutor { public void execute(Runnable runnable) { if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { runnable.run(); } }); } else { runnable.run(); } } } 这样,在事务方法中就可以直接使用这个执行器来提交需要在事务提交后执行的任务。 注意事项: -事务提交后执行操作,如果操作本身需要访问数据库,那么它将在新的事务上下文中执行(因为原事务已经提交),所以需要确保新操作事务管理(例如,可以单独使用一个事务)。 - 如果事务回滚,则不会执行afterCommit中的操作。 因此,根据需求,我们可以选择其中一种方法来实现。 回答结构: 1. 介绍需求背景 2. 提供两种方法(方法1和方法2)并给出代码示例 3. 注意事项 生成相关问题: 1. 在事务提交后执行操作如果发生异常会怎么样? 2. 如何在事务回滚后执行某些操作? 3. Spring Boot中如何保证事务提交后的操作是异步执行的?</think>### 如何在 Spring Boot 中实现事务提交后执行其他操作Spring Boot 中,可通过以下两种方式实现事务提交后执行操作--- #### **方法 1:使用 `TransactionSynchronizationManager`(原生支持)** 通过注册事务同步回调,在事务提交后触发自定义逻辑: ```java import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; @Service public class UserService { @Transactional public void createUser(User user) { // 1. 业务操作(如保存用户) userRepository.save(user); // 2. 注册事务提交后的回调 if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization( new TransactionSynchronization() { @Override public void afterCommit() { // 事务提交后执行操作 sendNotification(user); // 例如发送通知 log.info("事务提交,执行后续操作"); } } ); } } } ``` **原理**: Spring事务管理器通过 `TransactionSynchronization` 接口提供生命周期钩子。`afterCommit()` 方法会在事务成功提交后触发[^3]。 --- #### **方法 2:自定义事务后置执行器(封装复用)** 封装通用组件,简化代码: ```java @Component public class TransactionAfterCommitExecutor { public void execute(Runnable task) { if (TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.registerSynchronization( new TransactionSynchronizationAdapter() { @Override public void afterCommit() { task.run(); } } ); } else { task.run(); // 无事务时直接执行 } } } // 在 Service 中使用 @Service @RequiredArgsConstructor public class OrderService { private final TransactionAfterCommitExecutor afterCommitExecutor; @Transactional public void createOrder(Order order) { orderRepository.save(order); // 提交后生成报表 afterCommitExecutor.execute(() -> reportService.generateReport(order)); } } ``` **优势**: - 代码复用,避免重复注册回调[^4]。 - 支持无事务场景的降级处理。 --- #### **注意事项** 1. **执行上下文**: `afterCommit()` 中的操作**不在原事务内**,需独立处理事务(如添加 `@Transactional(propagation = Propagation.REQUIRES_NEW)`)。 2. **异常处理**: 若 `afterCommit()` 中的逻辑抛出异常,**不会回滚已提交事务**,需单独捕获处理。 3. **异步优化**: 耗时操作建议结合 `@Async` 实现异步执行,避免阻塞主线程: ```java afterCommitExecutor.execute(() -> { asyncService.sendEmail(user); // 异步方法 }); ``` --- ### 相关问题 1. **事务提交后的操作抛出异常会影响已提交的数据吗?** 不会。原事务提交,后续操作需独立处理异常[^3]。 2. **如何实现在事务回滚后执行特定逻辑?** 可重写 `TransactionSynchronization` 的 `afterCompletion()` 方法,根据状态码 `STATUS_ROLLED_BACK` 处理[^3]。 3. **非 Spring 管理的线程中能否使用 `TransactionSynchronizationManager`?** 不能。该工具类依赖 ThreadLocal 存储事务上下文,需确保操作Spring 事务线程内[^1][^2]。 4. **事务提交后的操作如何参与分布式事务?** 需通过消息队列(如 RabbitMQ/Kafka)或分布式事务框架(如 Seata)保障最终一致性。 [^1]: 多线程事务管理:Spring Boot 实现全局事务回滚 [^2]: Spring Boot 中的事务是如何实现的?懂吗? [^3]: Spring 事务管理器:等事务提交后执行方法 [^4]: 需要在事务提交后执行操作 - Spring Boot
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值