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

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

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
    评论
多线程异步操作回滚事务可以通过使用`@Transactional`注解和`TransactionSynchronizationManager`类来实现。具体步骤如下: 1.在异步方法上添加`@Transactional(rollbackFor = Exception.class)`注解,表示该方法需要进行事务管理,并且在出现异常时需要回滚事务。 2.在同步方法中调用异步方法时,使用`TransactionSynchronizationManager.registerSynchronization()`方法注册一个事务同步器,该同步器会在事务提交回滚时被调用。 3.在事务同步器中调用`TransactionSynchronizationManager.isActualTransactionActive()`方法判断当前是否有活动的事务,如果有,则调用`TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()`方法将事务标记为回滚状态。 下面是一个示例代码: ```java @Service public class MyService { @Autowired private MyAsyncService myAsyncService; @Transactional(rollbackFor = Exception.class) public void doSomething() { // 业务代码... try { // 数据库操作... } catch (Exception e) { // 调用异步方法完成数据库操作 myAsyncService.doSomethingAsync(); // 注册一个事务同步器 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCompletion(int status) { // 判断当前是否有活动的事务 if (TransactionSynchronizationManager.isActualTransactionActive()) { // 将事务标记为回滚状态 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } } }); } } } @Service public class MyAsyncService { @Async @Transactional(rollbackFor = Exception.class) public void doSomethingAsync() { // 异步方法业务代码... try { // 异步方法数据库操作... } catch (Exception e) { // 抛出异常,事务会自动回滚 throw new RuntimeException(e); } } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值