🥭
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