转载 

面试官:Java的循环遍历,如何保证每个循环体都是单独的事务?

分类:java    162人阅读    IT小君  2023-05-31 22:47

不知道大家在实际开发的过程中,有没有遇到过类似的情况:比如有这么一个定时任务,需要定时处理一些超时未付款的订单。然后你查询所有符合条件的记录(假设有10条记录),接着for循环遍历每一个订单,每个循环体都要执行大量的业务,比如商品库存回退,订单状态修改,业务流水添加,消息推送等。

你前五个循环都执行成功了,可是执行第六个循环的时候突然抛出一个异常,导致你前面五个执行成功的订单都事务回滚了,就有种三国的赤壁之战,曹军铁索连舟,一荣俱荣,一损俱损的感觉,是不是很蛋疼?你还真别笑,我接手公司项目的时候,还真的就看到前面的开发这样写代码。没办法,既然现在是咱接手,还就得老老实实的填坑了。

解决方案其实很简单,只需要一两段代码就能解决,本人亲测有效,当时测试的方式是:查询的10条记录,设置第6条出现异常,然后在10个循环都结束完后,发现只有第6条记录保持原样(异常时事务回滚),而它前面的5条和后面的4条都正常执行,并没有受影响。

我的项目用的是ssm框架,使用spring自带的定时任务,下面开始上伪代码:

先是OrderTimer.java类:该类是获取所有符合要求的记录,也就是获取这个集合,然后开始遍历执行每条符合要求的记录,注意具体执行的业务要封装到另一个方法中,也就是封装到业务层处理,不单单只是因为代码规范,更主要的是因为封装在另一个方法,才能更随心所欲的设置事务的传播属性。

package demo;
 
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import java.util.List;
 
@Component
public class OrderTimer {
 
    private static Logger logger = Logger.getLogger(OrderTimer.class);
 
    @Autowired
    private OrderService orderService;
 
    @Autowired
    private OrderMapper orderMapper;
 
    /**
     * 每隔1分钟执行未付款订单的关闭的操作
     */

    @Scheduled(cron = "0 0/1 * * * ?")
    public void closeOrders() {
        logger.info("--------开始每隔1分钟执行未付款订单的关闭的操作");
 
        //获取所有超时未付款的订单,这个需要根据你自己的实际情况编写,此处只是举例
        List list= orderMapper.listCloseOrder();
        if(list==null||list.size()<1){
            return ;
        }
 
        for (Order order : list) {
            orderService.closeOrder(order);
        }
    }
 
}

下面这个是实现层的代码,重点留意两个“关注点”:

package demo;
 
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
@Service
public class OrderServiceImpl implements OrderService {
 
    private static Logger logger=Logger.getLogger(OrderServiceImpl.class);
 
    @Autowired
    private OrderMapper orderMapper;
 
  /**
  这个注解很重要,意思是设置当前方法的事务传播级别为REQUIRES_NEW,表示当前方法内的所有事务都是独立的,不影响整体的事务。
  有的项目使用注解的方式配置当前方法传播属性会无效,此时可能需要你去你的spring-mybatis.xml文件中配置,效果是一样的
  */

    @Transactional(propagation = Propagation.REQUIRES_NEW)//关注点一!!!
    @Override
    public void closeOrder(Order order) {
 
        try{
 
  //这里,执行你自己的业务,比如商品库存回退,订单状态改变,操作流水等。
  //重点关注的是@Transactional注解和TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
    
 
            
        }catch (Exception e){
            logger.info("网络异常:"+e.getMessage());
            
            //这一段表示手动回滚事务,此处的try-catch,是表示当前方法如果出错了,
            //那我就自己消化这个异常,不再往外抛,处理异常的方式是手动回滚事务。
            //如此,每个循环体都自己处理自己的事务,不管成功与失败,都不影响整个循环
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//关注点二!!!
        }
 
    }
 
 
}

大致的逻辑便是如此,这种东西无法分享具体的代码,因为涉及到事务就得有数据库操作,有数据库操作就得建库建表,不可能全部写出来,那样不管对写的人还是看的人都很难受,所以不如省略具体的核心业务,只关注几个需要关注的点,然后以你现有的项目为基础实现出来并亲自测试一下。

当然,既然是伪代码,就需要有一定代码量的人才能脑补啊。

 

 

图片 你在看吗

转载于:http://mp.weixin.qq.com/s?__biz=MzIwNjg4MzY4NA==&mid=2247518232&idx=2&sn=533b91a4bb9ea0cae578975d100ac850&chksm=97181613a06f9f05cfca068cf505aba2c965df41cf2c982d46694914cf88d2b7edafe1706575#rd

点击广告,支持我们为你提供更好的服务

中小型创意设计服务公司网站模板

html5 svg夜空中星星流星动画场景特效

小众时尚单品在线电子商务网站模板

HTML5 Canvas竖直流动线条背景动画特效

网页设计开发公司网站模板

HTML5现代家居装潢公司网站模板

canvas炫酷鼠标移动文字粒子特效

HTML5数字产品服务公司网站模板

有机水果蔬菜HTML5网站模板

响应式咖啡饮品宣传网站模板

js+css3抽奖转盘旋转点餐代码

响应式太阳能能源公司网站模板

响应式时尚单品在线商城网站模板

现代时尚家具公司网站模板

css鼠标跟随文字模糊特效

jQuery右端悬浮带返回顶部特效

css+js实现的颜色渐变数字时钟动画特效

html5 canvas彩色碎片组合球形旋转动画特效

html5 canvas进度条圆环图表统计动画特效

html5图标下拉搜索框自动匹配代码

点击广告,支持我们为你提供更好的服务
 工具推荐 更多»
点击广告,支持我们为你提供更好的服务