支付宝一面多线程事务怎么回滚?用Transactional可以回去了!
背景介绍
1,最近有一个大数据量插入的操作入库的业务场景,需要先做一些其他修改操作,然后在执行插入操作,由于插入数据可能会很多,用到多线程去拆分数据并行处理来提高响应时间,如果有一个线程执行失败,则全部回滚。
2,在spring中可以使用 @Transactional 注解去控制事务,使出现异常时会进行回滚,在多线程中,这个注解则不会生效,如果主线程需要先执行一些修改数据库的操作,当子线程在进行处理出现异常时,主线程修改的数据则不会回滚,导致数据错误。
3,下面用一个简单示例演示多线程事务。 公用的类和方法/** * 平均拆分list方法. * @param source * @param n * @param * @return */ public static List> averageAssign(List source,int n){ List> result=new ArrayList>(); int remaider=source.size()%n; int number=source.size()/n; int offset=0;//偏移量 for(int i=0;i 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; } /** 线程池配置 * @version V1.0 */ 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(){} } /** 获取sqlSession * @author 86182 * @version V1.0 */ @Component public class SqlContext { @Resource private SqlSessionTemplate sqlSessionTemplate; public SqlSession getSqlSession(){ SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory(); return sqlSessionFactory.openSession(); } }
另外,如果你近期准备面试跳槽,建议在 Java面试库小程序在线刷题,涵盖 2000+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。 示例事务不成功操作 /** * 测试多线程事务. * @param employeeDOList */ @Override @Transactional public void saveThread(List employeeDOList) { try { //先做删除操作,如果子线程出现异常,此操作不会回滚 this.getBaseMapper().delete(null); //获取线程池 ExecutorService service = ExecutorConfig.getThreadPool(); //拆分数据,拆分5份 List> lists=averageAssign(employeeDOList, 5); //执行的线程 Thread []threadArray = new Thread[lists.size()]; //监控子线程执行完毕,再执行主线程,要不然会导致主线程关闭,子线程也会随着关闭 CountDownLatch countDownLatch = new CountDownLatch(lists.size()); AtomicBoolean atomicBoolean = new AtomicBoolean(true); for (int i =0;i list = lists.get(i); threadArray[i] = new Thread(() -> { try { //最后一个线程抛出异常 if (!atomicBoolean.get()){ throw new ServiceException("001","出现异常"); } //批量添加,mybatisPlus中自带的batch方法 this.saveBatch(list); }finally { countDownLatch.countDown(); } }); } for (int i = 0; i employeeDOList = new ArrayList<>(size); for (int i = 0; i employeeDOList) throws SQLException { // 获取数据库连接,获取会话(内部自有事务) SqlSession sqlSession = sqlContext.getSqlSession(); Connection connection = sqlSession.getConnection(); try { // 设置手动提交 connection.setAutoCommit(false); //获取mapper EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class); //先做删除操作 employeeMapper.delete(null); //获取执行器 ExecutorService service = ExecutorConfig.getThreadPool(); List> callableList = new ArrayList<>(); //拆分list List> lists=averageAssign(employeeDOList, 5); AtomicBoolean atomicBoolean = new AtomicBoolean(true); for (int i =0;i list = lists.get(i); //使用返回结果的callable去执行, Callable callable = () -> { //让最后一个线程抛出异常 if (!atomicBoolean.get()){ throw new ServiceException("001","出现异常"); } return employeeMapper.saveBatch(list); }; callableList.add(callable); } //执行子线程 List> futures = service.invokeAll(callableList); for (Future future:futures) { //如果有一个执行不成功,则全部回滚 if (future.get()<=0){ connection.rollback(); return; } } connection.commit(); System.out.println("添加完毕"); }catch (Exception e){ connection.rollback(); log.info("error",e); throw new ServiceException("002","出现异常"); }finally { connection.close(); } } // sql INSERT INTO employee (employee_id,age,employee_name,birth_date,gender,id_number,creat_time,update_time,status) values ( #{item.employeeId}, #{item.age}, #{item.employeeName}, #{item.birthDate}, #{item.gender}, #{item.idNumber}, #{item.creatTime}, #{item.updateTime}, #{item.status} )
数据库中一条数据:
测试结果:抛出异常,
删除操作的数据回滚了,数据库中的数据依旧存在,说明事务成功了。
另外,如果你近期准备面试跳槽,建议在 Java面试库小程序在线刷题,涵盖 2000+ 道 Java 面试题,几乎覆盖了所有主流技术面试题。
成功操作示例: @Resource SqlContext sqlContext; /** * 测试多线程事务. * @param employeeDOList */ @Override public void saveThread(List employeeDOList) throws SQLException { // 获取数据库连接,获取会话(内部自有事务) SqlSession sqlSession = sqlContext.getSqlSession(); Connection connection = sqlSession.getConnection(); try { // 设置手动提交 connection.setAutoCommit(false); EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class); //先做删除操作 employeeMapper.delete(null); ExecutorService service = ExecutorConfig.getThreadPool(); List> callableList = new ArrayList<>(); List> lists=averageAssign(employeeDOList, 5); for (int i =0;i list = lists.get(i); Callable callable = () -> employeeMapper.saveBatch(list); callableList.add(callable); } //执行子线程 List> futures = service.invokeAll(callableList); for (Future future:futures) { if (future.get()<=0){ connection.rollback(); return; } } connection.commit(); System.out.println("添加完毕"); }catch (Exception e){ connection.rollback(); log.info("error",e); throw new ServiceException("002","出现异常"); // throw new ServiceException(ExceptionCodeEnum.EMPLOYEE_SAVE_OR_UPDATE_ERROR); } }
测试结果:
数据库中数据:
删除的删除了,添加的添加成功了,测试成功。
原文链接:https://blog.csdn.net/weixin_43225491/article/details/117705686
游戏少年的成长登贝莱今天故事的主人公是曾经的天才少年奥斯曼登贝莱问题少年游戏王子,训练迟到,浪费天赋等等,一系列的问题词汇都出现在他的身上。在哈维没有回归巴萨执教的时候,天价的香球王已经沦为了替补球员
乒乓球的那些事之一N年前的夏季,市里成立了乒乓球俱乐部,活动场所在江北火车头体育馆,全城的爱好者都集中在这里,我也在那年调回家门口工作,被他们的活动吸引,便拿起了球拍。当时,人们从野路子来,向着规范
体育大观之武术(二)枪术一枪术枪术是以枪为器械的武术练习。按枪的种类,有大枪花枪二头枪等之分,使用上则均以拦拿扎为主。二枪法拦枪和拿枪又称圈枪,是防御之法,用时圈小迅速准确有力。扎枪是进攻之法,有上平中平
施罗德舍8400要260,但湖人就赚了吗?对着镜头,戴着墨镜,丹尼斯施罗德咬住了欧锦赛的铜牌。他有资格这么开心,因为那是他由亲手赢下,自2005年以来德国男篮在欧锦赛上拿到的第一枚奖牌。在8场欧锦赛里,施罗德场均能拿到22
世体主编拜仁意识到他们犯错了,马内很出色但不是莱万那种杀手直播吧9月21日讯世界体育报主编FrancescAguilar今天在推特发文,他表示拜仁在寻找莱万多夫斯基的替代者方面做错了。这位主编写道拜仁开始意识到,他们在寻找莱万的替代者时犯
B威廉姆斯马奎尔每天都全力以赴训练,C罗会和所有人交流在接受thesportsman的专访时,曼联小将布兰登威廉姆斯谈到了马奎尔和C罗。他表示,马奎尔每天都会全力以赴地投入训练,C罗则给了他很多的建议,也非常擅于和队友沟通。关于马奎尔
除了小行星撞地球和火山喷发恐龙蛋研究发现恐龙灭绝新因素用于本次研究的采自陕西山阳盆地的1件恐龙蛋化石标本。中新社记者孙自法摄中新网北京9月20日电(记者孙自法)从2。35亿年前的晚三叠世出现到6600万年前的白垩世消失,恐龙在地球上存
马斯克地球经济远未达到物理极限科学杂志自然(Nature)最近在推特上分享了一份回顾1972年罗马俱乐部增长的极限(LimitstoGrowth)报告的新分析,认为经济扩张不可能不受阻碍地继续下去,物理限制可能
外媒述评世界看好中国经济发展前景据英国泰晤士报网站9月17日报道,中国公布的8月份经济数据显示,中国经济表现出惊人韧性。数据表明,作为世界第二大经济体,中国经济步伐正在加速,从而提升了经济复苏的前景。最近的乐观数
阿德正式决定退役,太阳打算交易克劳德!霍华德和快船互相有意过去的一夜NBA又发生了不少事情,涉及了太阳爵士76人快船勇士湖人等多支球队。我给大家专门做了汇总,一起来看一下吧!1换1太阳打算交易克劳德名记文胖在今天参加节目时表示太阳队目前已
楼市回暖要失约,曹德旺预言成真?41家庭将面临什么结果?根据最新数据显示,70个大中城市中,不管是新房还是二手房,下跌的城市均已超过70,即便是一线城市,上海的房价环比上涨仅0。6,北京0。4,广州和深圳环比是下跌的,按照这个趋势来看,