本地多线程事务一致性控制

框架:springboot+mybatis-plus

在某些环境下面,我们需要使用一次性向数据库中插入大量数据,如果采用单线程,可能速度较慢,此时大部分童鞋第一时间就会想到采用多线程来进行操作。

但是多线程无法保证事务的一致性,造成数据库中出现大量的脏数据。经过研究,我们知道,如果多线程插入的数据使用的是同一个session,便可以保证事务的

一致性。

1、首先我们创建一个多线程的基础类

public  class  ThreadsTransactionBase  {

    @TableField(exist = false)
     private SqlSession sqlSession;

     @TableField(exist = false)
     private CountDownLatch count;

    @TableField(exist = false)
     private AtomicBoolean rollbackFlag = new AtomicBoolean(false);

    //省略get/set
   ....
}    
@TableField(exist = false)是为了解决该字段被框架识别为数据库中的字段,造成没有映射关系而报错。
2、创建处理切面
@Aspect
@Component
public class ThreadsTransactionAop {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    @Pointcut("execution(* com.example.demo.service.impl.Test1ServiceImpl.threadsTransaction(*))")
    public void point(){};

    @Around("point()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Connection connection = sqlSession.getConnection();
        connection.setAutoCommit(false);
        //获取参数
        ThreadsTransactionBase base = null;
        Object[] args = proceedingJoinPoint.getArgs();
        if (ObjectUtil.isNotEmpty(args)){
            for (Object arg : args) {
                if (arg instanceof ThreadsTransactionBase){
                    base = (ThreadsTransactionBase) arg;
                    base.setSqlSession(sqlSession);
                    base.setCount(new CountDownLatch(2));
                    break;
                }
            }
        }
        proceedingJoinPoint.proceed();
        if (null != base){
            try {
                base.getCount().await();;
            int i1 = 1 / 0;
                if (base.getRollbackFlag().get()){
                    //回滚
                    connection.rollback();
                }else{
                    //提交
                    connection.commit();
                }
            } catch (InterruptedException e) {
                //回滚
                connection.rollback();
            }
        }
        return null;
    }
}

3、具体service操作类

 /***
     * 多线程事务
     */
    @Override
    public void threadsTransaction( Test1Dto dto) throws SQLException {
        SqlSession sqlSession = dto.getSqlSession();
        Test1Mapper mapper = sqlSession.getMapper(Test1Mapper.class);
        List<Test1> list = dto.getList();
        //先插入first库
        mapper.insert(list.get(0));
        AtomicBoolean rollbackFlag = dto.getRollbackFlag();
        CountDownLatch count = dto.getCount();
        for (int i = 1; i < 3; i++) {
            int finalI = i;
            CompletableFuture.runAsync(()->{
                try {
                    mapper.insert( list.get(finalI));
                }catch (Exception e){
                    log.error("===========进来了=================",e);
                    rollbackFlag.set(true);
                }finally {
                    count.countDown();
                }
            });
        }
    }

 

 

 

 

posted @ 2022-07-20 15:09  炫舞风中  阅读(2000)  评论(0编辑  收藏  举报