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

多线程事务怎么回滚?说用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();     } }示例事务不成功操作  /**  * 测试多线程事务.  * @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);     } }
  测试结果:
  数据库中数据:
  删除的删除了,添加的添加成功了,测试成功。

未来不会失业的工作有哪些?近年来,随着高科技的发展,智能机器人在很多领域中已经投入使用了,减少劳动力成本的同时也造成了很多人失业,然而智能机器人的功能是有限的,有很多工作是代替不了的,所以从事这类工作的人们老爸今年59岁,一直在深圳的物流公司开货车,上个月被辞退,在深圳还能找到工作吗?深圳是一个年轻的城市,不缺年轻人,许多职位都招35岁以下的。一个50多岁的人来深找工作,即使以前开货车经验丰富,也难找,很少公司敢录用了!可以降低要求,找些搬运工,或者找些小厂的保现在学什么比较好找工作?很多。光学院就分不少计算机学院经管学院海尔家电学院物流学院美术学院国际学院至于专业就更多了个人建议你学学技术因为学校和海尔海信以及四方机场等技术单位都有很好的合作谢谢你的邀请回答玩在德阳工作5000元一月是什么水平?不晓得是到手5000还是应得5000,如果是前者应该超过了7080的德阳人了。德阳是个重工业城市,城里以二重东电东汽美丰等企业最为出名,工人应得工资超过5000,可他们光是公积金就女孩现在初一,预计考不上普高,现在怎样规划后面的人生?才初一,就这么给她定了吗?说个我自己的事情给你参考。我是女生,现在30多岁。我小学成绩很烂,真的很烂,都不及格的那种。上课总睡觉,每回放学,教室里就我一个人了,连扫地的同学都走光了坐标潍坊,算是小三线城市吧,工作轻松早八晚五从不加班,公司管一顿午饭,一个月四千五算少吗?卧槽,头条里这么多装逼的,我也来装一下,希望我能装的比你们更成功,装逼开始潍坊从西边的西外环路到东边的潍县中路之前的房产全是我承包开发的项目,我坐拥潍坊180套房子,名下300家公转业士官到银行工作,想辞职,应该怎么办?有个兄弟曾经就有过这种遭遇。他是士官三期,干了12年后选择安置,当时想去事业单位,结果因为打分打不过人家,最后只能选择国企。到他选的时候,只有三家国企供他选,一家是本地的轴承厂,半广西哪个市最重视教育?个人感觉,柳州市最重视教育。我是桂林人,县城的,儿子是在柳州的高中考上大学的。为什么会出现这样的情况呢?在桂林,很多人这样认为,柳州公立学校好,桂林私立学校好。柳州公立的高中柳州高为什么有人说广西人有很多需要过的节?因为过节好啊!我小时候最喜欢过节了,因为过节家里会做大餐吃,以及一些糕点,小时候每年都在期盼着各种大大小小的节,而且过节一家人每个人都开心,当然要把这些节日传承下去。在我们那,除了60岁的母亲要找个老伴,如果你是儿女会支持吗?为什么?会支持的。我的父亲2000年正月十九去世了,母亲今年94岁了,身体很好,耳不聋眼不花,说话声音洪亮,思维清淅。只是背有些驼了。父母是小时候(三五岁)定的娃娃亲,虽然父亲受过高等教育可以用深圳的公积金交惠州的房贷吗?我们都知道,在惠州买房的主力是深圳客,在购房者中占比近六成。2017年,深莞惠中四城新房市场中,供应量仅惠州增长,深圳东莞中山均下降。惠州供应量更是连续5年均为4城第一!惠州住宅成
攀枝花,西昌,米易。三个地方哪个更适合退休后养老?这三个地方都小住过。要单说气候环境米易排第一,蔬菜水果很新鲜。但是米易就那么大,也就河滨边晒太阳,时间一长也寂寞。周边农家乐价格不便宜。还有待进一步开发建设丰富多彩的老年公寓。第二执业药师是鸡肋职业吗?之所以有人认为执业药师是鸡肋,原因有几个。1。参加考试门槛比较低,通过率相对还是比较高的,之所以每年通过率20左右,主要在于报考的人太多了,很多人基础相对较差,如果按照本科以上药学古人讲好女不观灯,好男不鞭春,是什么道理?鞭春是什么意思?伊朗公共场合中的男女界限非常严格,与男子待遇大不相同,女子连看球赛曾经也被禁绝,已知近年有位女球迷为了抗议政府此项规定怒而自焚。我国封建社会比之进步的多,但是女子同样不能随便出去,郑州人民医院平均奖高还是郑州中心医院平均奖高?两个医院应该差别不大。郑州市中心医院前身是郑州市第四人民医院,其患者的主要是西郊,比如纺织系统啊和西郊的一些大企业的职工。而且经过多年的医疗服务,口碑和生意还可以。郑州市人民医院前你拍过最好的照片是什么?你好,我是一名摄影爱好者,很高兴回答这个问题。非常愿意用自己手机拍摄的照片在这里与大家一起分享,但愿让你感到美。手机拍照好的照片太多了,也不知道你喜欢什么景色,我先给您看一下我的家你见过最有财运的人是怎样的?我讲讲我朋友的财运,简直是颠覆我的认知。我朋友现在退休了,每个月有一万多的退休金,到现在我都没搞明白她怎么就那么年轻就退休,还能拿到那么多的工资,各种节日还有各种补助,冬天取暖费,为什么邮政银行那么不遗余力的为保险拉业务?各家银行都在拉保险。只是很多时候银行压根不告诉你那是保险而已。很多人认可保险,但就是听不得保险两个字,银行会说明白前五年不能取,会告诉你满期后能取出多少,但很少明确告诉人们产品具体什么是倒春寒?倒春寒就是春天的气候应该是温暖的,但是,它却乍暖还寒。春天开始于每年农历的2月末3月初,这个时间段的气候温度变化反差较大,冷空气活动频繁。这个时间段,人们体验最敏感最深。早中晚的气老年人再婚家庭里,老年女性最后悔的事是什么?最后悔的事是她没有得到再婚男人的尊重和爱,反被人利用做了人家的免费保姆。对于老年女性再婚,老头再好,最后结局大部分不乐观。我周边有好几对再婚老人,婚后生活相辅相成,过得还好,可到将沧州石家庄天津,哪里值得我用一生积蓄买套房子呢?当然是天津了。现在沧州,石家庄跟天津是没法比的,要拿出来一生积蓄买房子的话,这三个城市里面,应该首选天津。天津是中国四大直辖市之一,城市级别定位很高,现在天津经济正处于调整期,房子山东正科退休工资4800,什么水平?退休工资按地区和从事的职业有关系。在山区县城正科退休工资4800元属正常。不能与一二线城市及金融国企等相比。真要是4800的话确实不多,还没有老师多呢,我们东营这边刚退休的老师55