2019.04.07
文章目錄
- 前言
- 原理
- 方案
-
- 事務@Transactional
- JOIN FETCH
-
- 場景一:@Query或Native SQL
- 場景二:JPA Criteria API或Spring Specification API
- @NamedEntityGraph
- @FetchProfile
前言
Spring+Hibernate的項目,裡面大量用到
FetchType.LAZY
,懶加載實體成員。新需求開發一旦用到lazy成員,就會報
org.hibernate.LazyInitializationException
的異常。示例如下:
@Entity
@Table(name = "order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", referencedColumnName = "id")
private Product product;
}
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column
private String name;
@Column
private Float price;
}
原理
先看看Hibernate文檔1 2:
A “fetch” join allows associations or collections of values to be initialized along with their parent objects using a single select.
[1]: Hibernate Query HQL
[2]: Hibernate Fetch Strategies
JOIN FETCH中的fetch,是可以在單條select語句中,初始化對象中的關聯或集合。
如示例中
Order
的
product
成員,它是lazy成員,預設情況下是不會被初始化的,也就是說如果通過
getProduct()
通路成員的時候,就會報
LazyInitializationException
的異常。
方案
利用JPA的JOIN FETCH就可以擷取lazy成員[3][4]。
[3]: Stackoverflow about Join Fetch
[4]: Hibernate Get and Load Difference
事務@Transactional
如果在同一個事務上下文内,是可以擷取到lazy成員的,但在長事務或者多線程的場景下,這種方法就不合适3:
@Transactional
public void runWithinTransaction() {
Order order = orderService.getOne(1);
System.out.println(order.getProduct());
}
[5]: Stackoverflow about Transaction and Thread
JOIN FETCH
join fetch在JPA的sql裡可以很自然地實作,但在Criteria API中得采用
FetchParent#fetch
API實作[6][7]
[6]: FetchParent API
[7]: Stackoverflow about Criteria Join Fetch
場景一:@Query或Native SQL
select o from Order o join fetch o.product p where o.id = :id
場景二:JPA Criteria API或Spring Specification API
(root, query, criteriaBuilder) -> {
root.fetch("product"); // JOIN FETCH
//...
}
@NamedEntityGraph
@NamedEntityGraph(
name = "order-entity-graph",
attributeNodes = {
@NamedAttributeNode("product")
}
)
public class Order { //... }
@NamedEntityGraph
需要與
@EntityGraph
配合使用,上例即為
@EntityGraph(value = "order-entity-graph")
@FetchProfile
留給讀者自行探索
- 1 ↩︎
- 2 ↩︎
- 5 ↩︎