Grails中Domain对象的事务控制及同一对象的重复提交

主要对本次开发中遇到的两个问题进行说明,两个方面:

1、Grails Domain事务控制

2、在一个流程中同一个Domain对象的重复提交

 

业务描述

对商品信息进行批量导入,需对批量导入记录导入批次,实现对该批次数据中统计,包括:导入共多少条数据,其中成功了多少条,失败了多少条。

>1、如果商品满足导入要求(如商品种类,区域等判断),则对商品进行导入,导入时需对本系统中数据和另一个业务系统数据进行修改,并保证两个业务系统中数据是一致的(同时成功或者失败);对另一业务系统数据修改通过调用接口方式进行;

1.1、修改成功,记录为成功;

1.2、修改失败、记录为失败;

>2、如果商品不能满足导入要求(如商品种类,区域等判断),则对商品不进行导入,记录为失败;


功能实现

 上传需要导入的文件,对上传的文件进行解析,相关解析数据保存至list中,然后对list进行循环。以下为伪代码说明:

private Long saveList(List<String> list){
        if(list.size()>0){
            // 生成导入批次 ,设置该批次总数
            BatchDomain batch = new BatchDomain();
            batch.count = list.size();
            batch.save(flush: true, failOnError: true);

            //成功条数
            int sucCount = 0;
            //失败条数
            int failCount = 0;
            //对 list进行循环
            for(String productId:list){
                Boolean flag = changeProduct(productId, batch);
                if(flag)
                    sucCount = sucCount + 1;
                else
                    failCount = failCount + 1;
            }
            //修改导入批次的成功条数和失败条数
            batch.sucCount = sucCount;
            batch.failCount = failCount;
            batch.save(flush: true, failOnError: true);
        }
    }

    private boolean changeProduct(String productId, BatchDomain batch){
        boolean flag = false;
        //调用方法 checkProduct()判断是否满足导入要求,如果满足要求
        if(checkProduct(productId)){
            DetailDomainA.withTransaction { status ->
                try{
                    //修改本系统数据
                    DetailDomainA detailA = new DetailDomainA();
                    detailA.productId = productId;
                    detailA.batch = batch;
                    detailA.save(flush: true, failOnError: true);
                    DetailDomainB detailB = new DetailDomainB ();
                    detailB.productId = productId;
                    detailB.batch = batch;
                    detailB.save(flush: true, failOnError: true);

                    //调用其他业务系统接口修改数据
                    boolean thirdFlag = ThirdServiceInterface.updateTT(productId);
                    if(thirdFlag){
                        flag = true;
                    }else{
                        status.setRollbackOnly();
                    }
                }catch(Exception ex){
                    ex.printStackTrace();
                    status.setRollbackOnly();
                }
            }
        }
        return flag;
    }


以上为实现代码

但是当调用第三个接口异常需要对回滚时,报错如下:
Transaction rolled back because it has been marked as rollback-only
解决方法:
对方法 changeProduct 进行修改,修改后为:
@Transactional(propagation = Propagation.REQUIRES_NEW)
private boolean changeProduct(String productId, BatchDomain batch){
}

修改后,系统不再包原来错误,但又报一下错误:
a different object with the same identifier value was already associated with the session
解决方法:
修改方法 saveList(), 修改后方法如下:
private Long saveList(List<String> list){
if(list.size()>0){
                   // 生成导入批次 ,设置该批次总数
                   BatchDomain batch = new BatchDomain();
                   batch.count = list.size();
batch.save(flush: true, failOnError: true);

//成功条数
int sucCount = 0;
//失败条数
int failCount = 0;
//对 list进行循环
for(String productId:list){
                   Boolean flag = changeProduct(productId, batch);
         if(flag)
                            sucCount = sucCount + 1;
         else
         failCount = failCount + 1;
}
//修改导入批次的成功条数和失败条数
batch.sucCount = sucCount;
batch.failCount = failCount;
         batch = batch.merge();
return batch.id
}
}
}









  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值