多线程统一提交数据或回滚数据

在多线程下,统一提交各个子线程的任务。
先上代码

package security.study.mp.servers.Imp;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import security.study.mp.dao.IdworkMapper;
import security.study.mp.entity.Idwork;
import security.study.mp.servers.IdworkService;

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * author : LuoPan
 * date : 2021/8/11
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class IdworkServiceImpl extends ServiceImpl<IdworkMapper, Idwork> implements IdworkService {

    /**
     * 注入线程池 从线程池中获取线程
     */
    @Autowired
    private ThreadPoolTaskExecutor testThreadPoll;

    /**
     * 数据库事务管理
     */
    @Autowired
    private DataSourceTransactionManager transactionManager;

    /**
     * dao 层 操作数据
     */
    @Autowired
    @SuppressWarnings("ALL")
    private IdworkMapper idworkMapper;

    // 锁
    private final Lock lock = new ReentrantLock();

    // 构建数据用 忽略
    private final Random random = new Random(10);

    @Override
    public void manyThreadInsert() {
        // 相当于一个 flag
        AtomicBoolean atomicBoolean = new AtomicBoolean(true);
        // 计数线程数
        AtomicInteger atomicInteger = new AtomicInteger(0);
        // 构建一个 外层(主线程的)Condition 通过这个 Condition 进入等待和 唤醒
        Condition condition = lock.newCondition();
        // 存入 子线程 的 Condition 装入到集合
        AtomicReferenceArray<Condition> list = new AtomicReferenceArray<>(16);
        //  线程 数量,第一次弄太大,导致异常
        int size = 5;
        // for 循环构建线程
        for (int i = 0; i < size; i++) {
            // 构建 子 线程的 Condition
            Condition condition1 = lock.newCondition();
            int finalI = i;
            // 存入到 AtomicReferenceArray
            list.set(finalI, condition1);
            // 调用线程池进行 任务
            testThreadPoll.execute(() -> {
                log.info("线程内的finalI:{}", finalI);
                // 这个是我自己构建的实体类
                Idwork idwork = new Idwork();
                idwork.setClassNo(random.nextInt());
                idwork.setGradeYear(random.nextInt());
                idwork.setName(random.nextInt() + "student");
                idwork.setSex((short) 0);
                // 数据库的事务
                DefaultTransactionDefinition def = new DefaultTransactionDefinition();
                // 3.设置事务隔离级别,开启新事务
                def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                // 4.获得事务状态
                TransactionStatus status = transactionManager.getTransaction(def);
                    lock.lock();
                try {
                    // 插入数据,不提交
                    idworkMapper.insert(idwork);
                    // 先加 atomicInteger 然后获取其值
                    int current = atomicInteger.addAndGet(1);
                    log.info(String.valueOf(current));
                    // 判断 是否都进行到待 提交数据阶段
                    if (current == size) {
                        // 唤醒 主线程
                        condition.signal();
                    }
                    // 当前线程 等待
                    list.get(finalI).await();
                    // 等待结束后 判断是否统一提交数据
                    if (atomicBoolean.get()) {
                        // 统一提交
                        transactionManager.commit(status);
                    } else {
                        // 统一失败 回滚
                        transactionManager.rollback(status);
                    }
                } catch (Exception e) {
                    // 出现异常的 情况 设置回滚
                    atomicBoolean.set(false);
                    // 首先当前线程回滚
                    transactionManager.rollback(status);
                } finally {
                    // 当前线程 释放锁
                    log.info("子线程完成!");
                    lock.unlock();
                }

            });
        }
        try {
            lock.lock();
            // 主 线程等待
            condition.await();
            // 被唤醒后 主 线程去 唤醒子线程 进行统一的 提交 或回滚
            atomicBoolean.set(false);
            for (int i = 0; i < size; i++) {
                list.get(i).signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 当前线程释放锁
            log.info("完成");
            lock.unlock();
        }
    }
}

里面的 AtomicReferenceArray 为了应该可以换成 ArrayList ,没测试。
自己测试中出现的问题是。
1.开始时 线程数弄得高 ,结果中间获取sqlsession 连接出了问题,导致异常。线程开的不要太高。
2.理论上可能出现的情况 ,由于最后是for循环唤醒的,所以有可能导致一个唤醒,但是另一个没唤醒。

我的线程池

package security.study.config;

import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * author : LuoPan
 * date : 2021/8/12
 */

@Component
@EnableAsync
public class ThreadPool {

    private final static Integer CorePoolSize = 20;
    private final static Integer MaxPoolSize = 40;
    private final static Integer QueueCapacity = 99999;
    private final static String ThreadNamePrefix = "pool";

    @Bean(name = "testThreadPoll")
    public ThreadPoolTaskExecutor creatExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CorePoolSize);
        executor.setMaxPoolSize(MaxPoolSize);
        executor.setQueueCapacity(QueueCapacity);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        executor.setThreadNamePrefix(ThreadNamePrefix);
        return executor;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于MyBatis多线程批量插入回滚的问题,可以使用数据库事务来实现。以下是一个示例代码: ```java import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.TransactionIsolationLevel; import org.apache.ibatis.session.TransactionIsolationLevel; import org.apache.ibatis.session.TransactionIsolationLevel; import org.apache.ibatis.transaction.Transaction; import org.apache.ibatis.transaction.TransactionFactory; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import javax.sql.DataSource; import java.util.List; public class MyBatisBatchInsert { public void batchInsert(List<YourObject> objects) { SqlSessionFactory sqlSessionFactory = ...; // 初始化SqlSessionFactory try (SqlSession sqlSession = sqlSessionFactory.openSession()) { DataSource dataSource = sqlSession.getConfiguration().getEnvironment().getDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Transaction transaction = transactionFactory.newTransaction(dataSource, TransactionIsolationLevel.REPEATABLE_READ); try { YourMapper yourMapper = sqlSession.getMapper(YourMapper.class); for (YourObject obj : objects) { yourMapper.insert(obj); } transaction.commit(); // 提交事务 } catch (Exception e) { transaction.rollback(); // 回滚事务 throw e; } } } } ``` 在上述示例中,我们使用了MyBatis的事务管理机制,通过开启事务、执行批量插入操作、提交事务和回滚事务来实现多线程批量插入的回滚处理。请根据实际情况进行适当调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值