解决多线程批量插入中的事物一致性问题

在开发当中我们,我们有时为了加快执行速度,会使用到多线程!尤其在大量数据插入数据库时,我们需要使用多线程进行批量插入,加快程序的执行效率!

但是由于多线程中每个线程的事物是不一致的导致程序不一致!为了保证多个线程执行插入时,事物的一致性!我们需要保证所有事务统一操作。

实现思路:

1、编程式事务,通过代码控制事务的提交和回滚

2、获取每个线程的执行结果

3、根据每个线程执行结果判断是否需要回滚!

4、捕获到异常时也回滚

具体实现代码

@Service
@Slf4j
@DS(DynamicDatasourceConstants.DMB_DB)
public class TestManyThreadInsert {
    private final AbnormalNotPresentDao abnormalNotPresentDao;
    private final SqlSession sqlSession;

    public TestManyThreadInsert(AbnormalNotPresentDao abnormalNotPresentDao, SqlSession sqlSession) {
        this.abnormalNotPresentDao = abnormalNotPresentDao;
        this.sqlSession = sqlSession;
    }

    /**
     * 多线程处理数据
     * @param dataList 插入数据库的数据
     */
    @DS(DynamicDatasourceConstants.DMB_DB)
    public void saveBatch(List<AbnormalNotPresentPo> dataList) {

        // 获取数据库连接,获取会话(内部自有事务)
        final String push = DynamicDataSourceContextHolder.push(DynamicDatasourceConstants.DMB_DB);
        Connection connection = null;
        try {
            connection = sqlSession.getConnection();
            final ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNamePrefix(
                    "algorithmParamConfig-threadName").build();
            int threadNum = 5;
            final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(threadNum, threadNum, 10000L,
                    TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), namedThreadFactory,
                    new ThreadPoolExecutor.AbortPolicy());
            List<List<AbnormalNotPresentPo>> splitList = averageAssign(dataList, threadNum);
            //监控子线程执行完毕,再执行主线程,要不然会导致主线程关闭,子线程也会随着关闭
            CountDownLatch countDownLatch = new CountDownLatch(splitList.size());
            AtomicBoolean atomicBoolean = new AtomicBoolean(true);
            // 设置手动提交
            connection.setAutoCommit(false);
            abnormalNotPresentDao.removeById(BigInteger.valueOf(1619972395408429056L));
            List<Future<Boolean>> futures = new ArrayList<>();
            for (int i = 0; i < threadNum; i++) {
                if (i == splitList.size() - 1) {
                    atomicBoolean.set(false);
                }
                List<AbnormalNotPresentPo> list = splitList.get(i);
                Future<Boolean> future = threadPoolExecutor.submit(new Callable() {
                    @Override
                    public Object call() throws Exception {
                        try {
                            //最后一个线程抛出异常
                            if (!atomicBoolean.get()) {
                                throw new BizException(1000255, "出现异常");
                            }
                            //批量添加,mybatisPlus中自带的batch方法
                            return abnormalNotPresentDao.saveBatch(list);
                        } finally {
                            countDownLatch.countDown();
                        }
                    }
                });
                futures.add(future);
            }
            //执行子线程
            for (Future<Boolean> future : futures) {
                if (!Boolean.TRUE.equals(future.get())) {
                    connection.rollback();
                    return;
                }
            }
            connection.commit();
            //当子线程执行完毕时,主线程再往下执行
            countDownLatch.await();
            log.info("执行主线程");
        } catch (Exception e) {
            try {
                connection.rollback();
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            log.info("线程{}====插入数据错误", Thread.currentThread().getName());
            e.printStackTrace();
        } finally {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 平均拆分list方法.
     *
     * @param source
     * @param n
     * @param <T>
     * @return
     */
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {
        List<List<T>> result = new ArrayList<List<T>>();
        int remaider = source.size() % n;
        int number = source.size() / n;
        int offset = 0;//偏移量
        for (int i = 0; i < n; i++) {
            List<T> value = null;
            if (remaider > 0) {
                value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
                remaider--;
                offset++;
            } else {
                value = source.subList(i * number + offset, (i + 1) * number + offset);
            }
            result.add(value);
        }
        return result;
    }
}

上面是主要代码,其他代码和往常crud一样!

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值