【问题标题】:Spring Data, JPA @OneToMany Lazy fetch not working in Spring BootSpring Data,JPA @OneToMany Lazy fetch 在 Spring Boot 中不起作用
【发布时间】:2018-04-03 16:03:46
【问题描述】:

我在FabricRollFabricDefect 之间有@OneToMany 关系。

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "fabric_roll_id", referencedColumnName = "fabric_roll_id")
private Set<FabricDefect> fabricDefects = new HashSet<>();

问题是当我通过JpaRepository 函数获得FabricRoll

findAll()

关联 FabricDefect 也已加载。

我只想加载 FabricRollFabricDefect 应该在调用函数 getFabricDefect() 时加载

FabricRollServiceImpl 类

@Component
public class FabricRollServiceImpl implements IFabricRollService{
    @Autowired
    FabricRollRepository fabricRollRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public List<FabricRoll> getAllFabricRoll() {
        FabricRoll fabricRoll1 = new FabricRoll();
        fabricRoll1.setBatchNo("34344");
        fabricRoll1.setLotNo("425");
        fabricRoll1.setPoNo("42");
        fabricRoll1.setRollLength(2343);
        fabricRoll1.setRollNo("356");
        fabricRoll1.setRollWidth(60);
        fabricRoll1.setStyleNo("354");

        FabricDefect fabricDefect = new FabricDefect();
        fabricDefect.setDefectNote("note");
        fabricDefect.setDefectPoint(3);
        fabricDefect.setSegment(3);
        fabricDefect.setYard(42);


        Set<FabricDefect> fabricDefects = new HashSet<>();
        fabricDefects.add(fabricDefect);


        fabricRoll1.setFabricDefects(fabricDefects);

        addFabricRoll(fabricRoll1);

        FabricRoll fabricRoll = null;


        return fabricRollRepository.findAll();
    }

@Override
public void addFabricRoll(FabricRoll fabricRoll) {
    fabricRollRepository.save(fabricRoll);
}

}

断点:

控制台:

【问题讨论】:

  • 这是 OneToMany,你为什么使用 JoinColumn ?
  • 显示你在FabricDefect类中的内容
  • 如果你去掉@Transactional注解,你会看到你会得到LazyInitializationException,这意味着集合没有被加载。
  • 这里是同一问题的答案stackoverflow.com/a/42584774/5289288

标签: spring hibernate spring-data-jpa lazy-loading


【解决方案1】:

不需要使用@JoinColumn,也不需要实例化fabricDefects

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<FabricDefect> fabricDefects ; 

this 问题中查看更多信息。

【讨论】:

    【解决方案2】:

    FabricDefect 类:

    @ManyToOne
    @JoinColumn(name = "fabric_roll_id")
    private FabricRoll roll;
    

    FabricRoll 类:

    @OneToMany(mappedBy = "roll")
    private Set<FabricDefect> fabricDefects;
    

    默认情况下,集合是延迟加载的,只有在调用 getFabricDefects 方法时,JPA 才会查询数据库。 您可以自己启用日志记录。

    【讨论】:

      【解决方案3】:

      我在this tutorial找到了解决方案。

      你必须修改FabricRollOneToMany映射如下:

      @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "fabricRoll")
      private Set<FabricDefect> fabricDefects;
      

      FabricDefectManyToOne 如下(如果您将fabric_roll_id 字段包含在您的实体中,请记住删除它):

      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = "fabric_roll_id")
      private FabricRoll fabricRoll;
      

      而且您不需要在getAllFabricRoll() 函数之前添加@Transactional(propagation = Propagation.REQUIRED)

      【讨论】:

        【解决方案4】:

        它似乎是一个调试神器。

        在调试时,由于事务仍处于打开状态,被监视的延迟加载的实体属性会在断点求值时被加载。

        要检查“生产”行为,您应该在断点之前插入 em.detach 语句或使用日志记录(如 Manza 建议的那样)并检查 em.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(fabricRoll1.fabricDefects()) 在分离实体上返回 false。

        (记得注入EntityManager,例如声明@PersistenceContext private EntityManager em;

        【讨论】:

          猜你喜欢
          • 2018-12-09
          • 2020-07-11
          • 1970-01-01
          • 2021-12-19
          • 2019-05-17
          • 2016-10-04
          • 2018-11-14
          • 1970-01-01
          • 2016-09-18
          相关资源
          最近更新 更多