支付宝一面多线程事务怎么回滚?用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
在快手,嗅年味撰文文烨豪编辑吴先之尽管年味越来越淡已经成为近两年大众语境的共识,但在线上又是另一番局面。随着新年越来越近,不少App图标都穿上了新衣,各互联网平台的春节活动也已步入白热化阶段。而
年景走,春节去南华泡黑泥温泉2023年春节即将来临,你是否也想去一个有风的地方看山看水看风景,听风听雨听明月?这个春节假期,不如来楚雄南华黑泥温泉,感受不一样的年味。楚雄州南华黑泥温泉位于南华县一街乡团山村委
辽宁男篮完败广东男篮的原因找到了2023年1月18日,号称CBA春晚的辽粤大战如期进行了,通过一场全方面全过程全员性的完败,辽宁男篮如愿输掉了本场比赛。很多辽宁老球迷都知道,辽宁队有个特点,就是愿意给人惊喜,尤其
这个春节,我们一起去白沙!后疫情时代,白沙作为全国休闲农业与乡村旅游示范点,开启了新的征途。春节前后,随着旅游业市场不断调整适配,短途游日渐红火,白沙成为家庭休闲娱乐亲子游玩品尝特色美食的首选之地。小编捋出
中国足球烂到根部,媒体人圈内都知道刘奕有问题,但没人敢说李铁被带走后,紧接着中国足球协会第十一届执委会成员原秘书长刘奕也被带走了,另外中国足协常务副秘书长兼国管部部长陈永亮也接受了审查,事实说明,这件事背后的大人物还没有被挖出。斗胆猜测
澳网丨14次征战大满贯终进16强,29岁的中国金花朱琳大器晚成突破自我钱江晚报小时新闻记者曹林波北京时间1月20日晚,在2023年澳网女单第三轮的一场焦点大战中,中国金花朱琳苦战三盘,鏖战至墨尔本当地时间接近凌晨2点,最终76(3)1664击败了世界
诺基亚C12手机发布IT之家1月19日消息,HMDGlobal在2023年推出了一款廉价的Android12Go版手机诺基亚C12。诺基亚C12搭载了6。3英寸HD分辨率的LCD显示屏,机身尺寸为16
璀璨濠江多元韵味绘芳华大三巴是澳门最受欢迎的景点之一。欧家威,澳门广州社团总会副会长澳门工商联会理事长。无论是米其林星级餐厅,还是街边的手推车小食,都演绎出澳门的美食气质。何东图书馆。品尝美味是澳门旅游
自然论文格陵兰冰盖20012011年比20世纪平均高1。5C中新网北京1月19日电(记者孙自法)国际著名学术期刊自然最新发表一篇气候变化研究论文指出,对公元1100年至2011年格陵兰中北部的温度重建显示,格陵兰冰盖的近期温度是过去1000
编辑说湖南少儿出版社开启一场从自然百科到历史人文的美妙旅程中国国家地理手绘百科视频加载中一套给孩子的中国文化中国历史大画卷,开启一场从自然百科到历史人文的美妙旅程。青藏高原上,让欧洲植物猎人为之疯狂的美丽植物是什么?明明不起眼的胡椒,在西方竟然曾经和黄金一样
赏年俗看年戏美心红酒小镇举办特色村晚活动现场。杨孝永摄1月19日,由涪陵区文化和旅游发展委员会区农业农村委员会蔺市街道办事处指导,蔺市街道泡桐村主办,蔺市街道文化服务中心蔺市街道新时代文明实践所协办,美心红酒小镇景区