Java 多线程事务回滚 ——多线程插入数据库时事务控制

背景

日常项目中,经常会出现一个场景,同时批量插入数据库数据,由于逻辑复杂或者其它原因,我们无法使用sql进行批量插入。串行效率低,耗时长,为了提高效率,这个时候我们首先想到多线程并发插入,但是如何控制事务呢 … 直接上干货

实现效果
  • 开启多条子线程,并发插入数据库
  • 当其中一条线程出现异常,或者处理结果为非预期结果,则全部线程均回滚
代码实现
@Service
public class CompanyUserBatchServiceImpl implements CompanyUserBatchService {
    private static final Logger logger = LoggerFactory.getLogger(CompanyUserBatchServiceImpl.class);

    @Autowired
    private CompanyUserService companyUserService;

    @Override
    public ReturnData addNewCurrentCompanyUsers(String params) {
        logger.info("addNewCompanyUsers 新增参保人方法");
        logger.info(">>>>>>>>>>>>参数:{}", params);
        ReturnData rd = new ReturnData();
        rd.setRetCode(CommonConstants.RETURN_CODE_FAIL);
        if (StringUtils.isBlank(params)) {
            rd.setMsg("入参为空!");
            logger.info(">>>>>>入参为空。");
            return rd;
        }

        List<CompanyUserResultVo> companyUsers;
        try {
            companyUsers = JSONObject.parseArray(params, CompanyUserResultVo.class);
        } catch (Exception e) {
            logger.info(">>>>>>>>>入参格式有误: {}", e);
            rd.setMsg("入参格式有误!");
            return rd;
        }


        //每条线程最小处理任务数
        int perThreadHandleCount = 1;
        //线程池的最大线程数
        int nThreads = 10;
        int taskSize = companyUsers.size();

        if (taskSize > nThreads * perThreadHandleCount) {
            perThreadHandleCount = taskSize % nThreads == 0 ? taskSize / nThreads : taskSize / nThreads + 1;
            nThreads = taskSize % perThreadHandleCount == 0 ? taskSize / perThreadHandleCount : taskSize / perThreadHandleCount + 1;
        } else {
            nT
Java多线程中,事务回滚需要特殊的处理方式。在传统的单线程环境中,可以使用@Transactional注解来控制事务,并在出现异常进行回滚。然而,在多线程环境中,@Transactional注解不会生效,因此需要采取其他方式来实现事务回滚。 一种常见的方式是使用ThreadLocal来管理事务。ThreadLocal是一个线程局部变量,可以在每个线程中存储独立的数据副本。通过将事务相关的数据存储在ThreadLocal中,可以确保每个线程都有自己的事务上下文,并且不会相互干扰。 具体实现步骤如下: 1. 在主线程中开启事务,并将事务相关的数据存储在ThreadLocal中。 2. 创建子线程,并将ThreadLocal中的事务数据传递给子线程。 3. 在子线程中执行数据库操作,并在出现异常进行回滚。 4. 在主线程中根据子线程的执行结果决定是否提交或回滚事务。 下面是一个示例代码,演示了如何在Java多线程中实现事务回滚: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class TransactionDemo { private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<>(); public static void main(String[] args) { try { // 获取数据库连接 Connection connection = getConnection(); // 开启事务 connection.setAutoCommit(false); // 将连接存储在ThreadLocal中 connectionHolder.set(connection); // 创建子线程 Thread childThread = new Thread(() -> { try { // 获取子线程中的连接 Connection childConnection = connectionHolder.get(); // 执行数据库操作 // ... // 模拟出现异常 throw new SQLException("Simulated exception"); // 提交事务 childConnection.commit(); } catch (SQLException e) { e.printStackTrace(); try { // 回滚事务 connection.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } }); // 启动子线程 childThread.start(); // 等待子线程执行完毕 childThread.join(); // 根据子线程的执行结果决定是否提交或回滚事务 if (childThread.isAlive()) { connection.rollback(); } else { connection.commit(); } } catch (Exception e) { e.printStackTrace(); } finally { // 关闭连接 Connection connection = connectionHolder.get(); if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } private static Connection getConnection() throws SQLException { // 连接数据库的代码 return DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password"); } } ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值