HibernateのFetchMode
1. 序章
この短いチュートリアルでは、 @ org.hibernate.annotations.Fetchアノテーションで使用できるさまざまなFetchMode値を見ていきます。
2. 例の設定
例として、IDと一連の注文の2つのプロパティを持つ次のCustomerエンティティを使用します。
@Entity
public class Customer {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy = "customer")
@Fetch(value = FetchMode.SELECT)
private Set<Order> orders = new HashSet<>();
// getters and setters
}
また、ID、名前、およびCustomerへの参照で構成されるOrderエンティティを作成します。
@Entity
public class Order {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
// getters and setters
}
次の各セクションでは、データベースから顧客を取得し、すべての注文を取得します。
Customer customer = customerRepository.findById(id).get();
Set<Order> orders = customer.getOrders();
3. FetchMode.SELECT
Customer エンティティで、注文プロパティに@Fetchアノテーションを付けました。
@OneToMany
@Fetch(FetchMode.SELECT)
private Set<Orders> orders;
@Fetch を使用して、Customer。を検索するときにHibernateがプロパティを取得する方法を説明します。
SELECT を使用すると、プロパティを遅延ロードする必要があることを示します。
これは、最初の行について次のことを意味します。
Customer customer = customerRepository.findById(id).get();
注文テーブルとの結合は表示されません。
Hibernate:
select ...from customer
where customer0_.id=?
そしてそれは次の行のために:
Set<Order> orders = customer.getOrders();
関連する注文に対する後続のクエリが表示されます。
Hibernate:
select ...from order
where order0_.customer_id=?
Hibernate FetchMode.SELECT は、ロードする必要のあるOrderごとに個別のクエリを生成します。
この例では、Customersをロードするための1つのクエリと、注文コレクションをロードするための5つの追加クエリを提供します。
これはn+1選択問題として知られています。1つのクエリを実行すると、nの追加クエリがトリガーされます。
3.1. @ BatchSize
FetchMode.SELECT には、@BatchSizeアノテーションを使用したオプションの構成アノテーションがあります。
@OneToMany
@Fetch(FetchMode.SELECT)
@BatchSize(size=10)
private Set<Orders> orders;
Hibernate は、sizeパラメーターで定義されたバッチで注文コレクションを読み込もうとします。
この例では、注文が5つしかないため、1つのクエリで十分です。
引き続き同じクエリを使用します。
Hibernate:
select ...from order
where order0_.customer_id=?
ただし、実行されるのは1回だけです。これで、クエリは2つだけになります。1つは Customer をロードし、もう1つは注文コレクションをロードします。
4. FetchMode.JOIN
FetchMode.SELECT はリレーションを遅延ロードしますが、 FetchMode.JOIN はそれらを熱心にロードします。たとえば、結合を介して:
@OneToMany
@Fetch(FetchMode.JOIN)
private Set<Orders> orders;
これにより、CustomerとそのOrderの両方に対して1つのクエリが実行されます。
Hibernate:
select ...
from
customer customer0_
left outer join
order order1
on customer.id=order.customer_id
where
customer.id=?
5. FetchMode.SUBSELECT
orders プロパティはコレクションであるため、FetchMode.SUBSELECTを使用することもできます。
@OneToMany
@Fetch(FetchMode.SUBSELECT)
private Set<Orders> orders;
SUBSELECTはコレクションでのみ使用できます。
この設定では、 Customer:の1つのクエリに戻ります。
Hibernate:
select ...
from customer customer0_
そして、今回は副選択を使用して、Orderの1つのクエリを実行します。
Hibernate:
select ...
from
order order0_
where
order0_.customer_id in (
select
customer0_.id
from
customer customer0_
)
6. FetchMode対。 FetchType
一般に、 FetchMode は、 Hibernate がデータをフェッチする方法(選択、結合、または副選択)を定義します。 一方、 FetchType は、Hibernateがデータを熱心にロードするか遅延してロードするかを定義します。
これら2つの間の正確なルールは次のとおりです。
- コードがFetchModeを設定しない場合、デフォルトは JOIN であり、FetchTypeは定義どおりに機能します
- FetchMode.SELECTまたはFetchMode.SUBSELECTが設定されている場合、FetchTypeも定義どおりに機能します
- FetchMode.JOIN が設定されている場合、 FetchType は無視され、クエリは常に熱心になります
詳細については、Hibernateでの熱心な/遅延読み込みを参照してください。
7. 結論
このチュートリアルでは、 FetchMode のさまざまな値と、それらがFetchTypeとどのように関連しているかについて学習しました。
いつものように、すべてのソースコードはGitHubで利用できます。