由于LazyInitializationException

时间:2018-10-09 13:08:32

标签: hibernate spring-data hibernate-onetomany

我必须在前端显示一些数据,这些数据是由两个实体组合而成的。这两个实体具有这样的关系:

@Entity
@Table(name="T_LOAD_ORDERS")
@Data
public class LoadOrders {
    .
    .
    .
    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="SUPERVISOR")
    private MdUser supervisor;
    .
    .
    .
}

@Entity
@Table(name="T_MD_USER")
@Data
public class MdUser {

    @Id
    @Column(name="USER_ID")
    private String userId;
    .
    .
    .
    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    private List<OrderStates> orderStates;

    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="SUPERVISOR")
    private List<LoadOrders> loadOrders;

    @OneToMany(fetch=FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    private List<Staff> staffs;
}

因此,我必须从LoadOrders实体获取数据,并从MdUser获取userId。我使用Spring的JPARepository,因此在LoadOrders实体上调用findAll()。到目前为止,这很好。但是,当我添加以下几行代码时:

if (loadOrderEntity.getSupervisor() != null) {
    MdUser user = loadOrderEntity.getSupervisor();
    this.supervisor = user.getUserId();
} else {
    this.supervisor = null;
}

我收到此异常:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.XXXX.XX.XXXX.data.entity.MdUser.orderStates, could not initialize proxy - no Session

好吧,我想我很聪明地将命名的fetchtype更改为eager,但是如代码所示,该实体中有更多的懒惰提取。将它们全部更改为渴望听起来对我来说很愚蠢,而且也不起作用:

Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [de.fraport.bvd.mobisl.data.entity.MdUser.staffs, de.fraport.bvd.mobisl.data.entity.MdUser.orderStates]

那我该怎么办?

编辑

在Piotr Podraza暗示将@Transactional放在调用数据的方法之后,我更改了从数据库读取的代码,如下所示:

@Transactional(readOnly=true)
@GetMapping("/dispo/orderViewList")
private String showOrderList(@RequestParam("page") Optional<Integer> page, Model model) {
    page.ifPresent(p -> currentPage = p);

    Page<LoadOrders> pagedList = orderRepository.findAll(PageRequest.of(currentPage - 1, INITIAL_PAGE_SIZE));
    List<LoadOrder> orderList = service.createLoadOrderPage(pagedList); 

    model.addAttribute("page", orderList);
    model.addAttribute("currentPage", currentPage);
    model.addAttribute("totalPages", pagedList.getTotalPages());
    return "/dispo/orderViewList";
}

orderRepository扩展了JPARepository,findAll()方法是Spring提供的实现。但这仍然行不通。

@EnableTransactionManagement由我的JPAConfig类提供,该类导入到主应用程序类中,如下所示:

@SpringBootApplication
@Import(value=JPAConfig.class)
public class WebApplication {

    @Autowired
    private JPAConfig config;

    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

2 个答案:

答案 0 :(得分:0)

您在这里有两个选择:

1)保持延迟加载集合并修复代码,使其在会话中运行。

2)更改访存类型,以便它能迅速加载-这种方法需要将MdUser类中的收集类型从List更改为Set,因为您不能同时提取多个袋子。有关该问题的更多信息,请点击此处阅读:https://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html

答案 1 :(得分:0)

要执行@Transactional批注,必须将@EnableTransactionManagement批注添加到AppConfig文件中。

谈到Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [de.fraport.bvd.mobisl.data.entity.MdUser.staffs, de.fraport.bvd.mobisl.data.entity.MdUser.orderStates]

发生这种情况的原因是,在休眠状态下,您实际上不是使用List而是使用Bag,它们不是带有可能重复项的有序集合。在MdUser类中,您具有与同一属性相关的两个属性:

@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
private List<OrderStates> orderStates;

@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="USER_ID")
private List<Staff> staffs; 

因此,在Eager的情况下,Hibernate不知道如何将它们同时演化为Basgs。为避免此问题,至少有两种方法可使Hibernate将这些属性解析为真实的Hibernate列表:

  1. 为每个实体添加排序,即(假设Staff具有此属性)

    @OneToMany(fetch=FetchType.EAGER)
    @JoinColumn(name="USER_ID")
    @OrderBy("POSITION")
    private List<Staff> staffs;
    
  2. List替换为Set。如果您真的不需要任何订购,那么 使用Set代替List,这将自动强制休眠 将集合识别为休眠集。可以避免 提取过程中出现歧义

希望这会有所帮助