您的位置:首页 > 编程语言 > Java开发

javax.persistence.RollbackException: Transaction marked as rollbackOnly异常出现的原因以及避免方法

2016-10-12 12:24 555 查看
这次的需求是实现导入功能,要求:如果导入的内容以及存在,那就以excel表格的形式反馈给用户,并且告知用户每一行的错误原因;如果该条记录数据库中不存在,那么就添加到数据库中。

一开始,我的思路是在执行save操作时用try-catch包围,如果catch到了异常,那么就将这个对像放到errors中,在最后将errors导出成excel。

但是问题来了,由于我的repository是继承自JPARepository的,并且为了提高插入的效率,在service中加了@Transactional(noRollbackFor = Exception.class)注解。正是因为加了这个注解,所以导致了javax.persistence.RollbackException: Transaction marked as rollbackOnly异常的发生。

下面先来举个小列子

@Transactional(noRollbackFor = Exception.class)

Public void A(){

for(int 1=0;i<10;i++)

try{

add(i);

}catch(Exception e){

输出(i);

}

}

@Transactional

Public void add(int i){

if(i>5)

   Throw a exception//假设抛出一个异常

将 i 插入到数据库中

}

在这种情况下就会出现javax.persistence.RollbackException: Transaction marked as rollbackOnly异常。

当在A方法中执行B方法时,虽然A方法加了 noRollbackFor = Exception.class ,但是由于调用的B方法没有加,并且在B中抛出了异常,那么就会报这个错误,也无法达到我的目的,即插入0到5这几个数字,而是会全部回滚。

我的需求跟这个类似,我本来想通过try-catch来捕捉到插入失败的对象,然后分析异常原因,再导出给用户,好让他们修改完之后再上传。但是我调用Jpa的sava方法,它本身的实现中就加了@Transactional,没有加noRollbackFor = Exception.class,因此即便我在service方法中加了@Transactional(noRollbackFor = Exception.class),也会回滚。

下面我的解决方法是进行预处理,在插入之前先进行判重,即将考试表中的考题拿出来,为了提高判重效率,先将String的考题构建Hash值,然后进行比较,这样的比较速度会大大提高。代码如下

@Transactional
public Map<String, Object> save(List<Exam> exams) {
Map<String, Object> error = new HashMap<>();

List<Exam> errors = new ArrayList<>();
List<String> errorMsgs = new ArrayList<>();

List<String> tests = repo.findTests();

List<Integer> testHashcodes = new ArrayList<Integer>();
for (String test : tests) {
testHashcodes.add(test.hashCode());
}

int hashcode = -1;
for (Exam exam : exams) {
hashcode = exam.getTest().hashCode();
if (testHashcodes.contains(hashcode)) {
errors.add(exam);
errorMsgs.add("题目重复");
} else {
repo.save(exam);
testHashcodes.add(hashcode);
}
}
error.put("errors", errors);
error.put("errormsg", errorMsgs);

return error;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐