开启独立事务


大概的结构是这样的,有两个service,一个是ExcelImportService,另一个是MaterialService,调用过程就是ExcelImportService作为入口调用MaterialService,二话不说直接上代码

ExcelImportService.java

/**
     * Excel导入
     *
     * @param excelFile excel文件
     * @param params    参数
     * @return
     */
    public Object excelImport(MultipartFile excelFile, Map<String, Object> params) {
        // 返回错误信息  key -> sheet名称 , value -> 对应sheet行错误信息
        Map<String, List<String>> result = new HashMap<>(16);
        // 导入物料表(这里只是模拟一下数据,假装这个list里面有东西)
        List<MaterialViewModel> materials = new ArrayList<>();
        // 通过构造注入的MaterialService
        this.materialService.batchImport(materials, result);
        return result;
    }

MaterialService.java


/**
     * 批量导入
     *
     * @param viewModels 导入数据
     * @param result     返回异常记录
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchImport(List<MaterialViewModel> viewModels, Map<String, List<String>> result) {
        // 错误信息列表
        List<String> errorList = new ArrayList<>();
        // 新增物料
        if (viewModels != null && !viewModels.isEmpty()) {
            // 遍历数据
            for (int i = 0; i < viewModels.size(); i++) {
                MaterialViewModel temp = viewModels.get(i);
                try {
                    // AopContext提供的方法你可以在任何时候都能获取到代理对象,解决内部调用问题
                    String errorMessage = ((MaterialService) AopContext.currentProxy()).rowImport(temp);
                    // 错误信息不为空
                    if (!errorMessage.isEmpty()) {
                        errorList.add("第" + (i + 1) + "行," + errorMessage);
                    }
                } catch (Exception e) {
                    errorList.add("第" + (i + 1) + "行," + e.getMessage());
                }
            }
        }
        // 如果行错误信息不为空
        if (!errorList.isEmpty()) {
            result.put("物料表", errorList);
        }
    }

 /**
     * 单条excel行导入
     *
     * @param viewModel
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public String rowImport(MaterialViewModel viewModel) {
        StringBuilder errorMessage = new StringBuilder();
        try {
            // 物料编号
            if (StringUtils.isEmpty(viewModel.getMaterialCode())) {
                errorMessage.append("物料编码不能为空");
            }
            // 校验通过则添加
            if (errorMessage.length() == 0) {
                add(viewModel);
            }
            return errorMessage.toString();
        } catch (Exception e) {
            // 记录日志
            EvLog.error(e.getMessage());
            errorMessage.append(e.getMessage());
            // 手动回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return errorMessage.toString();
        }
    }

启动类上需要加上**@EnableAspectJAutoProxy(exposeProxy = true)**

返回结果如下
在这里插入图片描述
在这里插入图片描述
excel中一共有四条数据,有一条数据不正确,所以数据库只插入了三条

总结
当前应用场景的实现主要是通过Spring的事务注解@Transactional的propagation属性的Propagation.REQUIRES_NEW属性值,官方的解释如下
在这里插入图片描述
翻译一下就是创建一个新事务,如果存在,则挂起当前事务,再说细致一点就是它会启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行,但是值得注意的是Spring的@Transactional是基于AOP实现的,所以内部方法的调用是无法开启新的事务的,所以如果我们上述代码直接用batchImport()调用rowImport()是不会生成新事务的(具体的底层原因小伙伴可自行查阅资料,反正我是不知道233),但是为了业务的规范的统一,确实要放到一个service里面,所以就用了这一行代码((MaterialService) AopContext.currentProxy()).rowImport(temp),通过这行代码就解决了内部调用失效的问题

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值