首页 > 其他分享 >mybatis多线程插入数据表已经事务回滚

mybatis多线程插入数据表已经事务回滚

时间:2024-05-13 15:54:04浏览次数:10  
标签:回滚 java import util 数据表 threadTransaction org 多线程 transactionManager

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import java.util.function.BiFunction;

/**
 * mybatis批量操作工具类
 */
@Slf4j
@Component
public class MybatisBatchUtil {

    private static final int BATCH_SIZE = 2000;

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Resource
    PlatformTransactionManager transactionManager;

    @Autowired
    private Executor taskExecutor;

    public <T, U, R> void batch(List<T> dataList, Class<U> mapperClass, BiFunction<T, U, R> function) throws ApiException {
        if (dataList.size() <= BATCH_SIZE){
            batchSync(dataList, mapperClass, function);
        }else {
            batchParallel(dataList, mapperClass, function);
        }
    }

    public <T, U, R> void batchSync(List<T> dataList, Class<U> mapperClass, BiFunction<T, U, R> function) throws ApiException {
        SqlSession batchSqlSession = sqlSessionFactory.openSession();
        batchSqlSession.getConfiguration().setDefaultExecutorType(ExecutorType.BATCH);

        U mapper = batchSqlSession.getMapper(mapperClass);
        DefaultTransactionDefinition threadDef = new DefaultTransactionDefinition();
        threadDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus threadTransaction = transactionManager.getTransaction(threadDef);
        for (T t : dataList) {
            try {
                function.apply(t, mapper);
            } catch (Exception e) {
                transactionManager.rollback(threadTransaction);
                throw new ApiException("系统异常请联系管理员");
            }
        }
        transactionManager.commit(threadTransaction);
    }

    public <T, U, R> void batchParallel(List<T> dataList, Class<U> mapperClass, BiFunction<T, U, R> function) throws ApiException {
        SqlSession batchSqlSession = sqlSessionFactory.openSession();
        batchSqlSession.getConfiguration().setDefaultExecutorType(ExecutorType.BATCH);
        U mapper = batchSqlSession.getMapper(mapperClass);

        List<List<T>> phoneNumPartition = ListUtils.partition(dataList, BATCH_SIZE);

        Vector<Thread> threadVector = new Vector<>();
        CountDownLatch count = new CountDownLatch(phoneNumPartition.size());
        AtomicBoolean rollbackFlag = new AtomicBoolean(false);

        for (List<T> data : phoneNumPartition) {
            taskExecutor.execute(() -> {
                TransactionStatus threadTransaction = null;
                try {
                    Thread thread = Thread.currentThread();
                    threadVector.add(thread);
                    if (CollectionUtils.isEmpty(data)) {
                        return;
                    }

                    DefaultTransactionDefinition threadDef = new DefaultTransactionDefinition();
                    threadDef.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                    threadTransaction = transactionManager.getTransaction(threadDef);
                    for (T datum : data) {
                        function.apply(datum, mapper);
                    }
                    count.countDown();
                    LockSupport.park();
                    if (rollbackFlag.get()) {
                        transactionManager.rollback(threadTransaction);
                    } else {
                        transactionManager.commit(threadTransaction);
                    }
                } catch (TransactionException e) {
                    log.error("异步批量插入异常", e);
                    count.countDown();
                    rollbackFlag.set(true);
                    if(threadTransaction != null) transactionManager.rollback(threadTransaction);
                }
            });
        }
        try {
            count.await(30000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            rollbackFlag.set(true);
            log.error("导入时候线程阻塞异常", e);
        }
        for (Thread thread : threadVector) {
            LockSupport.unpark(thread);
        }
        if (rollbackFlag.get()) {
            throw new ApiException("系统异常请联系管理员");
        }
    }

标签:回滚,java,import,util,数据表,threadTransaction,org,多线程,transactionManager
From: https://www.cnblogs.com/MC-Bonnie/p/18189368

相关文章

  • C#多线程
    目录C#线程概述定义程序、进程、线程基本语法C#可以通过Thread、ThreadPool、Task(推荐)创建线程。前台线程和后台线程共享数据保护机制优缺点/应用场景优缺点常见的应用场景总结C#线程概述定义线程(thread)是计算机科学中将进程划分为两个或多个线程(实例)或子进程,由单处理器(单线程......
  • 多线程应用
    importtimeimportthreadingdeffunc_one(name):fornuminrange(1,6):print(f"{name}第{num}次执行")time.sleep(1)deffunc_two(name):fornuminrange(1,6):print(f"{name}第{num}次执行")time.sleep(1......
  • 爬虫多线程代码调试
    第一次调试fromthreadingimportThreadfromfake_useragentimportUserAgentimportrequestsfromtimeimportsleepforiinrange(1,11):url=f"https://www.hupu.com/home/v1/news?pageNo={i}&pageSize=50"headers={"User-......
  • C#实现多线程的几种方式
    思维导航前言多线程常用场景什么是进程?什么是线程?使用Thread类使用ThreadPool类使用Task类使用Parallel类拾遗补漏合集DotNetGuide技术社区交流群前言多线程是C#中一个重要的概念,多线程指的是在同一进程中同时运行多个线程的机制。多线程适用于需要提......
  • 最近在写一个网页,想谈谈数据表的关系
    一对多影片(一)--剧集(多)影片表idurltitle1url1title12url2title23url3title3剧集表idmovie_idurl11url121url233url341url4在上面两个表中,可见一个影片可以有多个剧集,在表的设计中应该在多的一方设置一的一方......
  • C#实现多线程的几种方式
    前言多线程是C#中一个重要的概念,多线程指的是在同一进程中同时运行多个线程的机制。多线程适用于需要提高系统并发性、吞吐量和响应速度的场景,可以充分利用多核处理器和系统资源,提高应用程序的性能和效率。多线程常用场景CPU密集型任务.I/O密集型任务.并发请求处理.大数......
  • 【专题】2022年智能汽车行业数字化人才白皮书报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=34111随着新一轮技术革命和产业变革的推动,以及国家政策的大力扶持,电动化、智能化、网联化已经成为汽车行业发展的新趋势。在这种背景下,各大企业纷纷争夺数字化人才,以推动产品的规模化落地和商业化创新应用。阅读原文,获取专题报告合集全文,解锁文末53......
  • 理解 iOS 中的多线程编程
    在iOS应用开发中,多线程编程是一项关键技术,可以帮助应用实现更好的性能和响应性。本文将详细解释iOS中的多线程编程,并讨论如何在应用中正确地使用多线程以提高性能和响应性。1.什么是多线程编程?多线程编程是指在一个应用程序中同时执行多个线程(线程是进程中的执行单元),从而实......
  • 【专题】2022年中国企业数字化学习行业研究报告PDF合集分享(附原数据表)
    报告链接:http://tecdat.cn/?p=32263多变,不确定性,复杂,模糊不清的新业务图景,加快了公司人才发展模式的数字化转变;疫情冲击离线运输与公司现金流量,消费者支出减少,机构表现受压,数字化学习突破;行业数字化水平不断提高,商业体系和学习体系之间的关联性不断加强,企业学情图谱不断完善; 阅......
  • 【专题】展望人工智能银行:当银行遇到AI报告PDF合集分享(附原数据表)
    原文链接:http://tecdat.cn/?p=32210在2016年,AlphaGo机器人打败了18届世界棋王李世石,成为了世界棋坛上最伟大的人物。阅读原文,获取专题报告全文,解锁154份文末人工智能银行相关报告。围棋是一种非常复杂的棋类,它要求有很强的直觉,想像力和策略性的思考,而这一切在很长一段时间里都......