范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

支付宝一面多线程事务怎么回滚?

  背景介绍
  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();     } } 示例事务不成功操作/**  * 测试多线程事务.  * @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}          )        
  数据库中一条数据:
  测试结果,抛出异常:
  删除操作的数据回滚了,数据库中的数据依旧存在,说明事务成功了。
  成功操作示例: @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);     } }
  测试结果:
  数据库中数据:
  删除的删除了,添加的添加成功了,测试成功。
  来源:blog.csdn.net/weixin_43225491/article/details/117705686

如果确诊病例再增加,兰州有可能会封城吗,你会赞同兰州封城吗?不能排除这种可能。首批大规模核酸检测以来,出现了二十多个阳性样本,其中也有环境样本。如果不能快速确定本次疫情的源头,未来防控会面临极大压力。目前虽然只有城区的几个小区采取了只进不出8万请了一个刑事律师,一共只会见了34次就开庭了,值吗?谢谢邀请!甭管花多少钱,刑辩律师在整个案件代理过程中,一般都只会会见委托人4次左右的样子,即便是10万20万的刑辩律师同样如此。如果你是在刚被抓进入看守所时请的律师,一般会在你刚进内蒙古巴彦淖尔的房价会不会跌回2015年的水平?会的。年轻人90不回来,最次在呼市工作成家,孩子不回临河,这家人不在临河消费。高考水平在内蒙古排名较差,孩子上小学就去呼市了。水深火热的地方,个人发展太难了,除了你的背景和银子丰厚当年那些下岗职工临近退休了,已办退休的人员退休工资有多少呢?国企破产倒闭,工人下岗失业,尤其是双职工家庭,一起下岗失业,生活艰难,有些是一家人在一个厂子,全家下岗失业,现实很残酷啊!有些人一家人在垄断企业,或者是公务员事业编,最近几十年,贫残疾人家里有车会被取消低保吗?残疾人属弱势群体,有的中重度残疾人由于没有正式工作有的会吃低保,也有的有残疾补助金。家中若有车者一般不符合低保条件,但有的人则是残疾人代步车就应另当别论了。我们南昌早年对经营拐的的该如何度过70岁以后的衰老岁月?今年虚岁七十一了,体能较比过去还是有些下降,前几年骑着单车游走国内外十多万公里,出版一本纪实游记四十八万字,现在每天吹萨克斯,四个小时,骑行三十多公里,晚间走步十公里,已经形成三十人到中年一事无成,难道要打工到老吗?说说我自己吧,81年的,41了,刚结婚几年,孩子三岁半。为什么这个话题扯到结婚生孩子呢,因为40之前一事无成,想早结婚没条件啊,好女孩也都不傻,前几年有多一事无成呢,600一个月的刚刚晋升为部门经理,应该做哪些事情?职场中,晋升为部门经理一般有两种情况跨部门提拔和本部门提拔。两者有一定区别,建议分别从以下几个方面考虑一跨部门提拔举例从市场销售部门提拔到人事部门。问题员工基本情况不了解工作流程工襄阳最有名的十大小吃是什么?襄阳是国家历史文化名城,历史悠久,美食也很丰富且别具风味特色。下边同城君帮你送上襄阳最有名的十大小吃。一襄阳豆腐面襄阳豆腐面是襄阳市的特色小吃之一。襄阳豆腐面的臊子比较讲究,里面有成都房价,这两年到底会不会降啊,刚需买房深入咨询?降是不可能的。目前国家对于房地产的要求就是未来只能维持小幅度上涨。用通胀来变相实现下跌。。什么意思?就是打个比方未来十年可能房子只按照目前的价格上涨了15,而你的工资得上涨1倍,收在中国,研究生和导师之间是一种什么样的关系?硕士研究生和导师的关系,像老板和员工的关系博士研究生跟导师的关系,像合作伙伴的关系。在大学里边,老师只给学生上课,面向全班同学,不负责具体的个别指导,所以大学里边都是老师和学生之间
重温雷锋日记争当雷锋传人经典诵读(17)要真正学到一点东西,就要虚心视频加载中学习内容雷锋日记(1962年3月x日)生活中一切大的和好的东西全是由小的不显眼的东西累积起来的。人若没干劲,好像没有蒸汽的火车头,不能动像没长翅膀的鸟,不能飞。视频加载中他是谁大结局种种迹象表明,真凶很可能是最不起眼的他他是谁仍然在持续更新,背后的那个他到底是谁,逐渐开始有了眉目。很多观众觉得更新得太慢了,恨不得一下冲到最后一集,看看结局。他到底是谁?这个问题,一直吊着大家的好奇心。也是观众追剧的热门展一票难求!各地延续博物馆热排队观展成常态视频加载中今年以来,各地掀起博物馆热,处处可见排队观展的火热场面。各大博物馆也纷纷拿出镇馆之宝,并创新观展方式,让观众看得过瘾,玩得高兴。在杭州工艺美术馆,200多名小学生在兴致勃新版出生医学证明4月1日启用视频加载中国家卫健委印发关于启用出生医学证明(第七版)的公告,并公布第七版出生医学证明样证式样。4月1日起,我国将启用第七版出生医学证明。第六版出生医学证明签发日期截至今年3月31文学枇杷膏阳光静静地从远方的山头上斜射下来,屋顶上的炊烟在母亲的火钳中静静地飘散着,猪偶尔从圈里传来哼哼的声音,鸡娃子们跟在母鸡的后面觅食,母亲坐在井水旁的椅子上劳作,美得像一幅画。火辣辣的补链强链为工业强基赋能产业链供应链安全稳定日益成为各方高度关注的重大问题。党的二十大报告指出,要着力提升产业链供应链韧性和安全水平。对此,要进一步增强忧患意识机遇意识,强化底线思维极限思维,主动识变应变浅析李梦四宗最,才知姚明是衰人女篮姑娘李梦的事件,已经持续多日,现在总结出其中的五宗最,与大家分享。第一最苦的是姚明作为篮协主席,本意是放狗看兔子,结果变成狗骑兔子,他首先要担用人失察之责,下属风流快活,老大辛湖南55岁巨婴熊丽啃完三任丈夫,啃94岁老母,从未工作一天当94岁的老母亲在为自己买菜做饭的路上摔倒骨折而需要做手术的时候,五十多岁的熊丽却拿不出手术费。原因无他,熊丽已经将母亲给她的钱全部挥霍殆尽,眼看着母亲在医院病床上呻吟,她只能拨通鲜菇杂谈剑16Part2口语话题解析汇总今天给大家分享剑16中的四道part2口语话题。第一题根据动词我们可以判断出这是一道事件题,描述你喜欢的一次逛景点的经历。通篇主要需要用过去时态来完成。给大家的参考素材是我几年前去这场听证会让人彻底领略了何为美式霸权TikTok首席执行官周受资在听证会上路透社图片中国网3月24日讯(记者蒋新宇)美国当地时间23日上午10时,美国华盛顿特区,TikTok首席执行官周受资出席美国国会众议院能源和商千味央厨拟定增募资不超5。9亿元2021年上市募3。34亿来源中国经济网中国经济网北京3月24日讯今日,千味央厨(001215。SZ)股价上涨,截至收盘报71。33元,涨幅0。10。昨晚,千味央厨披露2023年度向特定对象发行股票预案,本