所谓“抓取策略”,总要涉及两个问:
何时抓取(是否延迟加载)以及如果抓取
。这两点在Hibernate提供的注解上体现的非常明显。
Hibernate提供两套注解分别用来描述“何时抓取”和“如何抓取”。这样看起来非常条理和清晰。
但是JPA没有这么做。它只提供了fetch=FeatchType.LAZY or FetchType.EAGER.但是我们必须明白这两种选项对应的实际抓取策略是什么。
测试用例:
@Test public void testFetch(){ Session session = HibernateUtil.openSession(); Customer customer = session.get(Customer.class, 1); System.out.println(customer.getOrders());//是否延迟加载 session.close(); } |
一、JPA抓取策略
它对于lazy和eager只各提供一种抓取方法,不需要再指定“如何抓取”
1、fetch=FetchType.LAZY:何时抓取:lazy,如何抓取:select(默认)
@OneToMany(mappedBy = "customer", cascade = {CascadeType.ALL}, fetch=FetchType.LAZY) private Set<Order> orders = new HashSet<Order>(); |
2、fetch=FetchType.EAGER:何时抓取:eager,如何抓取:join
@OneToMany(mappedBy = "customer", cascade = {CascadeType.ALL}, fetch=FetchType.EAGER) private Set<Order> orders = new HashSet<Order>(); |
二、Hibernate抓取策略
1、延迟加载和非延迟加载
延迟
@OneToMany(mappedBy = "customer", cascade = {CascadeType.ALL}) @LazyCollection(LazyCollectionOption.TRUE) private Set<Order> orders = new HashSet<Order>(); |
非延迟
@OneToMany(mappedBy = "customer", cascade = {CascadeType.ALL}) @LazyCollection(LazyCollectionOption.FALSE) private Set<Order> orders = new HashSet<Order>(); |
3、抓取策略(*对多)
默认
@OneToMany(mappedBy = "customer", cascade = {CascadeType.ALL}) @LazyCollection(LazyCollectionOption.FALSE) @Fetch(FetchMode.SELECT) private Set<Order> orders = new HashSet<Order>(); |
关联查询
@Fetch(FetchMode.JOIN) |
子查询
@OneToMany(mappedBy = "customer", cascade = {CascadeType.ALL}) @LazyCollection(LazyCollectionOption.FALSE)//不是必须 @Fetch(FetchMode.SUBSELECT) private Set<Order> orders = new HashSet<Order>(); |
测试子查询需要查询列表
@Test public void testFetchList(){ Session session = HibernateUtil.openSession(); Query<Customer> query = session.createQuery("from Customer", Customer.class); List<Customer> list = query.list(); for (Customer customer : list) { Set<Order> orders = customer.getOrders(); for (Order order : orders) { System.out.println(order.getOrderNo()); } System.out.println(); } session.close(); } |
4、抓取策略(*对一)
测试用例
@Test public void testFetchOrder(){ Session session = HibernateUtil.openSession(); Order order = session.get(Order.class, 1L); System.out.println(order.getCustomer());//是否延迟加载 session.close(); } |
JPA策略:
1、何时抓取:eager,如何抓取:join(默认)
@ManyToOne(fetch=FetchType.EAGER) @JoinColumn(name="customer_id") private Customer customer; |
2、何时抓取:lazy,如何抓取:select
@ManyToOne(fetch=FetchType.LAZY) @JoinColumn(name="customer_id") private Customer customer; |
Hibernate策略:
1、代理延迟加载
@ManyToOne @JoinColumn(name="customer_id") @LazyToOne(LazyToOneOption.PROXY) @Fetch(FetchMode.SELECT) private Customer customer; |
2、很少使用,需要使用编译时字节码增强
@LazyToOne(LazyToOneOption.NO_PROXY) |
三、抓取策略的总结
1、JPA
属性:
1.1 *对一(默认非延迟、join):
fetch = FetchType.EAGER:非延迟、join
fetch = FetchType.LAZY:延迟、select、代理
1.2 *对多(默认延迟、select):
fetch = FetchType.EAGER:非延迟、join
fetch = FetchType.LAZY:延迟、select
2、Hibernate
2.1 延迟策略:
*对一
(默认非延迟):@LazyToOne(LazyToOneOption.XXX)
@LazyToOne(LazyToOneOption.PROXY)
@LazyToOne(LazyToOneOption.FALSE)
*对多
(默认延迟):@LazyCollection(LazyCollectionOption.XXX)
@LazyCollection(LazyCollectionOption.TRUE)
@LazyCollection(LazyCollectionOption.FALSE)
2.2 抓取策略:
*对一(默认join)
@Fetch(FetchMode.SELECT)
@Fetch(FetchMode.JOIN)
*对多(默认select)
@Fetch(FetchMode.SELECT)
@Fetch(FetchMode.JOIN)
@Fetch(FetchMode.SUBSELECT)