支付宝一面多线程事务怎么回滚?说用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); } }
测试结果:
数据库中数据:
删除的删除了,添加的添加成功了,测试成功。
版权声明:本文为CSDN博主「weixin_43225491」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_43225491/article/details/117705686
2023年,天梭表该怎么选?天梭哪个系列比较值得入手?最近经常在网上看到这样的言论,说天梭属于是屌丝手表,和DW卡西欧阿玛尼并驾齐驱,位列四大屌丝手表之中,说实话看到这样的言论确实给我气的不行,因为我戴的就是天梭!!!!!!!!!!只
A股注册制规则解读主板上市更包容板块定位更明晰前言2023年2月1日,中国证监会就全面实行股票发行注册制主要制度规则向社会公开征求意见(征求意见),标志着A股全市场注册制将正式展开。安永大中华区审计服务主管合伙人毛鞍宁表示全面
749元,先马黑钻1000W雪装版全模组电源发布IT之家2月8日消息,先马推出了黑钻1000W雪装版全模组电源,采用了纯白设计,首发价749元。先马黑钻1000W雪装版虽然不是ATX3。0标准,但标配了PCIe5。0显卡供电线,
活久见!武汉这家小贷公司通知用户不用还款!公司回应来了小贷领域出现活久见的新情况。近日一家小贷公司因进入清算阶段短信通知借款用户不用还钱了的消息持续发酵,引起广泛关注。贷款机构称顾客没有还款义务,这一情况在金融领域并不常见。消息传出后
人体从虚湿瘤,疾病诞生五大阶段,你发展到哪一阶段?分享百草益寿人体生病并非突然发生,都是由浅及深逐渐形成的。许多疾病的发生大致可分为,虚寒湿瘀瘤五阶段,中医上讲上工治未病,就是在疾病还没有严重爆发的时候,就给治好,而不是等到疾病发
三年后,微信视频号被称之为全村的希望,未来值得期待吗?对于任何一个拥有12亿以上月活用户的互联网产品来说,在它的基础上来开发任何一款新的产品,都有着天然的优势,微信视频号就属于这种里面的典型代表。作为承载了腾讯在短视频行业的希望,微信
在八维,大数据学出来做什么工作?现在的大数据技术发展很快,我们学了之后,能用它来做什么工作呢?大数据在抗疫中的应用不论走到哪里,进门前先拿出手机扫描健康码地方社区等工作人员通过大数据便可精准排查来往人员利用大数据
未来漫评人月两团圆,家国共情怀去年元夜时,花市灯如昼。月上柳梢头,人约黄昏后。又是一年元宵佳节,汤圆里的甜蜜家人围坐的温馨奔波旅途中的小梦想,如此种种,组成幸福的良宵。在这个诗意而浪漫的日子里,人们庆祝着万物复
蛋白质不够水来凑大家好,我是营养调理师空谷阿亮,今天的主题是缺乏蛋白质,为什么会水胖,现在进入主题你就是你吃出来的,也是你生活习惯培养出来的人体需要的养分是基因指定的,数量以及排列顺序都是被基因设
江西猪王,悬了一家走在悬崖边上的企业。1hr巨亏养猪大户正邦科技正在进入至暗时刻。1月31日,正邦科技公告称,预计2022年归属于上市公司股东的净利润亏损110亿元至130亿元扣除非经常性损益后
科学界的乌龙人们追踪了17年的外星信号,竟来自地球上的微波炉1998年,人们通过帕克斯天文台捕捉到了一个神秘的信号,这种信号和如今火热的快速射电暴十分相似,有一定的规律。由于它十分特殊,所以自从被发现以后就被持续追踪调查。不过随着时间的流逝