主要对本次开发中遇到的两个问题进行说明,两个方面:
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
}
}
}