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

这次的需求是实现导入功能,要求:如果导入的内容以及存在,那就以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;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值