使用spring-data-jpa碰到的坑

@Override
    public List<CgSubject> queryByYearId(Integer yearId) {
        Specification<CgSubject> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>(); // 所有的断言
            predicates.add(cb.equal(root.get("deleted"), 0));
            predicates.add(cb.equal(root.get("yearId"), yearId));
            predicates.add(cb.equal(root.get("status"), 1));
            return cb.and(predicates.toArray(new Predicate[0]));
        };
        List<CgSubject> cgSubjectList = cgSubjectMapper.findAll(specification);
        cgSubjectList.forEach(temp -> temp.setTempName((temp.getType() == 1 ? "线上-" : "线下-") + temp.getName()));
        return cgSubjectList;
    }

另外还有一段存储的代码

@Transactional
    public List<CgOrder> importGroupBuyOrderExcel(List<Map<String, Object>> rowList, User creator) {
        List<CgOrder> cgOrderList = transform(rowList);
        Integer state = cgOrderList.get(0).getState();
        for (CgOrder o : cgOrderList) {
            if (!state.equals(o.getState())) {
                throw new BusinessException(null, "所有订单的支付状态不统一");
            }
            CgProduct p = o.getCgProduct();
            cgProductRepository.save(p);
            o.setProductId(p.getId());
            o.setCreateName(creator.getUserName());
            cgOrderRepository.save(o);
            o.setOrderNo(AbstractTeacherTrainOrderService.getOrderNo(o.getId()));
            cgOrderRepository.save(o);
        }
        return cgOrderList;
    }

 

当然,第二段代码存储是有点问题,但不影响这个要说的这个问题,第一段代码我们通过spring jpa托管器获取到了cgSubject的列表,并对其名称进行更新,然后第二段代码中会在transform()方法中调用第一段代码,然后下面用spring jpa 进行save操作。这个时候会发现cgSubject也会被更新,原因就是用到了spring jpa托管器,在第一段代码更新name的时候相当于就会数据库的update操作,然后通过后面的save操作触发。

解决办法:

  1.可以通过cgSubject实体类增加冗余字段,然后用@Transient 标注。 

  2.可以不使用spring jpa托管器,通过本地sql来查询cgSubject列表(未尝试,但感觉可行)。

这算是刚用spring jpa 碰到的一个坑吧,用了两个小时才发现并解决问题。

上一篇:springclould gateway 配置


下一篇:关于jpa的Specification自定义函数,实现oracle的decode;以及如何在静态方法中调用注入的service