🥭
JPAのFetchTypeとは
FetchType
今まで多様なリレーショナルマッピングを勉強しながら説明してなかったこと一つがあります。それはFetchTypeというものです。このFetchTypeはJPAの性能を決めるとっても重要なものです。
-
FetchTypeはDBからデータを持ってくるための戦略を決めるものです。 -
FetchTypeにはEAGER戦略とLAZY戦略があります。
EAGERローディングとLAZYローディング

単純なMemberのデータだけを使用するビジネスロジックでMemberを照会する時Teamも一緒に照会しなければならないですか?
LAZYローディング(FetchType.LAZY)

@Entity
public class Member {
private String name;
@ManyToOne(fetch = FetchType.LAZY) // LAZY
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
member.getTeam(); // この時点ではProxy
memger.getTeam().getTeamName(); // この時点で初期化され本物のデータを持ってくる
- FetchType.LAZYを設定して照会する場合Proxyが照会される。
- 本物の値またはメソッドを使う前までは初期化されない。
- JPAのProxyとは編を参考してください
EAGERローディング(FetchType.EAGER)

@Entity
public class Member {
private String name;
@ManyToOne(fetch = FetchType.EAGER) // EAGER
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
-
Memberを照会する時Teamも即時に持ってくる。 -
@ManyToOneはEAGER戦略が基本値。 -
Member一個照会する時TeamもJOINを利用してクエリ一発で照会- JPAがやってくれる性能最適化:
em.find(Member.class, 1L)
- JPAがやってくれる性能最適化:
-
JPQLを使用するときは性能最適化してくれない
- JPQL :
select m from Member m;すると - SQL :
select * from Member;と翻訳される。 - つまり
Memberオブジェクト内にTeamオブジェクトがEAGERに設定されてるにも関わらずMemberのみを照会し、照会した後Member内のTeamがEAGERである事を確認し、また、クエリを投げTeamを照会する - また
MemberがいくつかあってTeamもいくつかある時Memberを照会するとその個々のMemberに関わっているTeamを呼び出すために考えられないクエリが追加で投げられる、詰まり、N+1問題が発生する。 - N+1問題は他の記事で詳しく説明します。
- JPQL :
まとめ
- なるべく実務ではLAZYローディングを使用することがいい。
- EAGERを適用すると予想できないクエリが投げられる。
- EAGERはJPQLでN+1問題を引き起こす。
-
@ManyToOne,@OneToOneは基本値がEAGER、LAZYに変更すべき -
@OneToMany,@ManyToManyは基本値がLAZY - 全てのリレーショナルマッピングでLAZYを使用しましょう。
- 実務ではEAGERではなくJPQLのfetch joinやエンティティグラフを使用しましょう。
select m from Member m join fetch Team;
Discussion