本地多线程事务一致性控制
框架: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();
}
});
}
}