多线程下保证数据库事务

本文介绍了在SpringBoot应用中如何获取SqlSession,配置线程池,以及实现多线程事务处理,包括如何手动提交、使用平均拆分列表和在遇到异常时回滚事务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

获取sqlSession

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
public class SqlContext {
   
    @Resource
    private SqlSessionTemplate sqlSessionTemplate;

    public SqlSession getSqlSession(){
        SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();
        return sqlSessionFactory.openSession();
    }
}

线程池配置

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 线程池配置
 */
public class ExecutorConfig {

    private static int maxPoolSize = Runtime.getRuntime().availableProcessors();

    private volatile static ExecutorService executorService;

    public static ExecutorService getThreadPool() {
        if (executorService == null) {
            synchronized (ExecutorConfig.class) {
                if (executorService == null) {
                    executorService = newThreadPool();
                }
            }
        }
        return executorService;
    }

    private static ExecutorService newThreadPool() {
        int queueSize = 500;
        int corePool = Math.min(5, maxPoolSize);
        return new ThreadPoolExecutor(corePool, maxPoolSize, 10000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(queueSize), new ThreadPoolExecutor.AbortPolicy());
    }

    private ExecutorConfig() {

    }
}

拆分新增List方法

    /**
     * 平均拆分list方法
     *
     * @param source 需拆分List
     * @param n      拆分份数
     * @param <T>    返回值
     * @return
     */
    public static <T> List<List<T>> averageAssign(List<T> source, int n) {

        List<List<T>> result = new ArrayList<>();

        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;
    }

多线程新增

    @Resource
    SqlContext sqlContext;

    /**
     * 测试多线程事务.
     *
     * @param employeeDOList
     */
    public void saveThread(List<Config> employeeDOList) throws SQLException {


        // 获取数据库连接,获取会话(内部自有事务)
        SqlSession sqlSession = sqlContext.getSqlSession();
        Connection connection = sqlSession.getConnection();
        try {

            // 设置手动提交
            connection.setAutoCommit(false);

            // 获取mapper层
            ConfigMapper employeeMapper = sqlSession.getMapper(ConfigMapper.class);

            //先做删除操作
            employeeMapper.deleteConfig(null);

            // 获取线程池
            ExecutorService service = ExecutorConfig.getThreadPool();


            List<Callable<Integer>> callableList = new ArrayList<>();
          
            // 拆分数据 5代表拆分成5份
            List<List<Config>> lists = averageAssign(employeeDOList, 5);

            for (int i = 0; i < lists.size(); i++) {
                List<Config> list = lists.get(i);
                Callable<Integer> callable = () -> employeeMapper.saveBatch(list);
                callableList.add(callable);
            }

            //执行子线程
            List<Future<Integer>> futures = service.invokeAll(callableList);
            for (Future<Integer> future : futures) {
                // 如果有一个执行不成功,则全部回滚
                if (future.get() <= 0) {
                    connection.rollback();
                    return;
                }
            }

            // 提交事务
            connection.commit();
            System.out.println("添加完毕");
        } catch (Exception e) {
            e.printStackTrace();
            // 失败回滚
            connection.rollback();
            throw new RuntimeException("出现异常");
        }
    }

参考

多线程事务如何回滚?说用 @Transactional 可以回去等通知了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值