【问题标题】:How to fix the most common LazyInitializationException - Hibernate JPA如何修复最常见的 LazyInitializationException - Hibernate JPA
【发布时间】:2020-02-16 14:23:56
【问题描述】:

我正在与 LazyInitializationException 作斗争。到目前为止,我已经阅读了所有关于此的文章,但不幸的是,我没有找到解决问题的方法。其中许多解决方案使用 EntityManager 或我不使用的东西。我正在通过 JPA 连接我的数据库。

我有几个实体,但问题只是其中两个:Order 和 OrderDetails。 当我从 DB 对象 Order 中获取信息时,我会尝试执行 order.getOrderDetails(),然后出现以下错误:

例外:

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.tradesystem.order.Order.orderDetails, could not initialize proxy - no Session

但它的工作方式相反:从 OrderDetails 对象我可以通过 objectDetail.getOrder() 获得订单。 更重要的是:由于我在另一个实体中使用它,我无法使用 Eager 加载。

这是我的订单类:

@Entity
@Data
@Table(name = "orders")
public class Order {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_id")
private Long id;

private LocalDate date;

@OneToMany(mappedBy = "order")
private List<OrderDetails> orderDetails;

@ManyToOne
@JoinColumn(name = "buyer_fk")
private Buyer buyer;

@ManyToOne
@JoinColumn(name = "supplier_fk")
private Supplier supplier;
}

OrderDao:

@Repository("orderDao")
public interface OrderDao extends JpaRepository<Order, Long> {

@Query(value = "SELECT * FROM orders " +
        "WHERE MONTH(orders.date) = ?1 AND YEAR(orders.date) = ?2",
        nativeQuery = true)
List<Order> getMonthOrders(int month, int year);
}

和订单详情:

@Entity
@Data
@Table(name = "orderDetails")
public class OrderDetails {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "order_details_id")
private Long id;

private BigDecimal quantity;

private BigDecimal sum;

@ManyToOne
@JoinColumn(name = "order_fk")
private Order order;

@ManyToOne
@JoinColumn(name = "product_fk")
private Product productType;

@OneToOne
@JoinColumn(name = "order_comment_fk")
private OrderComment orderComment;
}

以@Many 结束的关系默认是延迟加载的,那么为什么在我执行 .getOrderDetails() 时它不加载我的 OrderDetails 呢?

如果有任何帮助,我将不胜感激! PS。我是初学者,所以如果我解释的不够好,请不要犹豫提出一些问题。

【问题讨论】:

  • 你什么时候得到异常?它在服务中吗?控制器?它是事务上下文吗?
  • 服务中。不,它不是事务性上下文。
  • 真的有使用原生查询吗?否则你可以使用left join fetch order.orderDetails
  • 那么,您究竟提出了什么来代替原生查询呢?

标签: java spring hibernate jpa lazy-initialization


【解决方案1】:

使用这个

@Repository("orderDao")
public interface OrderDao extends JpaRepository<Order, Long> {

    @Query(value = "SELECT orders FROM Order orders LEFT JOIN FETCH orders.orderDetails " +
        "WHERE MONTH(orders.date) = ?1 AND YEAR(orders.date) = ?2")
    List<Order> getMonthOrders(int month, int year);
}

【讨论】:

  • 但它应该。也许你可以分享新的例外?此方法返回的所有订单都应初始化其 orderDetails 集合。
  • 新的异常和以前完全一样,没有任何改变。获取 Order 对象时 JOIN FETCH 应该同时加载 objectDetails,但事实并非如此。
  • 是所有订单都受影响还是只有少数?使用 OSIV 时,您必须小心,因为已经是会话/实体管理器一部分的实体对象在使用连接获取时未初始化。
  • 无论我尝试获得多少订单,同样的问题是当我只是检索一个特定订单(按 id)或其中几个(按选定月份)时。跨度>
  • Fetch 加入将从数据库中检索状态。集合未初始化的唯一原因是该订单对象是否来自一级或二级缓存。如果您之前在事务中加载了订单而没有 fetch 加入,它可能是一级缓存的一部分。我只能建议您在执行此查询之前尝试清除实体管理器以确保或在执行查询之前进行调试以检查一级缓存中的内容。如果没有更多细节或示例项目,这很难远程诊断
【解决方案2】:

我已经解决了这个问题。我在 CommandLineRunner 中运行一切。当我开始在主类中进行“尝试某事”的测试时,惰性异常消失了。

我的主课看起来像:

 @Bean
 public CommandLineRunner bookDemo(OrderDao orderDao, PriceDao priceDao, ProductDao productDao,
                                   OrderService orderService, InvoiceDao invoiceDao, InvoiceService invoiceService) {
                                   OrderService orderService, InvoiceDao     invoiceDao, InvoiceService invoiceService,
                                   ReportService reportService) {
     return (args) -> {

         List<Order> orders = orderDao.findByBuyerId(1L);

         for (Order order : orders) {
             orderService.payForOrde(order);
         }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 2014-10-21
    • 2019-06-27
    • 1970-01-01
    相关资源
    最近更新 更多