TL; DR
T findOne(ID id)
(古いAPIでのOptional<T> findById(ID id)
名前)/ (新しいAPIでの名前)はEntityManager.find()
、エンティティの熱心な読み込みの実行に依存しています。
T getOne(ID id)
エンティティの遅延読み込みEntityManager.getReference()
を実行することに依存しています。したがって、エンティティの効果的な読み込みを確実にするために、エンティティのメソッドを呼び出す必要があります。
findOne()/findById()
は、よりも明確で使いやすいですgetOne()
。
したがって、ほとんどの場合、を優先findOne()/findById()
してくださいgetOne()
。
APIの変更
少なくとも、変更された2.0
バージョンから。
以前は、インターフェースで次のように定義されていました。Spring-Data-Jpa
findOne()
CrudRepository
T findOne(ID primaryKey);
さて、findOne()
あなたが見つける単一のメソッドは、次のようCrudRepository
にQueryByExampleExecutor
インターフェースで定義されたものです:
<S extends T> Optional<S> findOne(Example<S> example);
これはSimpleJpaRepository
、CrudRepository
インターフェースのデフォルト実装であるによって最終的に実装されます。
このメソッドは検索例によるクエリであり、代わりに使用したくない。
実際、同じ動作のメソッドはまだ新しいAPIにありますが、メソッド名が変更されています。インターフェースで
からに名前が変更さfindOne()
れfindById()
ましたCrudRepository
。
Optional<T> findById(ID id);
これでが返されますOptional
。これは防ぐのにそれほど悪くはありませんNullPointerException
。
したがって、実際の選択は〜の間にOptional<T> findById(ID id)
なりT getOne(ID id)
ます。
2つの異なるJPA EntityManager取得メソッドに依存する2つの異なるメソッド
1)Optional<T> findById(ID id)
javadocによると、
エンティティをIDで取得します。
実装を調べてみるとEntityManager.find()
、取得の実行に依存していることがわかります。
public Optional<T> findById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return Optional.ofNullable(em.find(domainType, id));
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}
そしてここに宣言されem.find()
たEntityManager
メソッドがあります:
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties);
そのjavadocの状態:
指定されたプロパティを使用して、主キーで検索します
したがって、ロードされたエンティティを取得することは期待されているようです。
2)T getOne(ID id)
javadocが述べている間(強調は私のものです):
指定された識別子を持つエンティティへの参照を返します。
実際、参照用語は実際にはボードであり、JPA APIはgetOne()
メソッドを指定していません。
したがって、Springラッパーが何をするかを理解するために行う最善のことは、実装を調べることです。
@Override
public T getOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}
以下em.getReference()
は、次のEntityManager
ように宣言されたメソッドです。
public <T> T getReference(Class<T> entityClass,
Object primaryKey);
そして幸いにも、EntityManager
javadocはその意図をより明確に定義しています(強調は私のものです):
状態が遅延フェッチされるインスタンスを取得します。リクエストされたインスタンスがデータベースに存在しない場合、インスタンスの状態に最初にアクセスしたときに EntityNotFoundExceptionがスローされます。(永続化プロバイダーランタイムは、getReferenceが呼び出されたときにEntityNotFoundExceptionをスローすることが許可されています。)アプリケーションは、エンティティマネージャーが開いている間にアプリケーションからアクセスされない限り、デタッチ時にインスタンスの状態が利用可能であることを期待してはなりません。
したがって、呼び出しgetOne()
は遅延フェッチされたエンティティを返す可能性があります。
ここでは、遅延フェッチはエンティティの関係ではなく、エンティティ自体を参照しています。
これは、呼び出したgetOne()
後に永続コンテキストが閉じられた場合、エンティティがロードされない可能性があるため、結果は本当に予測できないことを意味します。
たとえば、プロキシオブジェクトがシリアル化されているnull
場合、シリアル化された結果として参照を取得できます。または、プロキシオブジェクトでメソッドが呼び出された場合、などの例外LazyInitializationException
がスローされます。
したがって、このような状況では、そのスローがEntityNotFoundException
使用する主な理由ですgetOne()
、エンティティが存在しない間はエラー状況が実行されない可能性があるため、データベース内に存在しないインスタンスを処理するする。
いずれの場合でも、その読み込みを保証するには、セッションが開いている間にエンティティを操作する必要があります。エンティティの任意のメソッドを呼び出すことで実行できます。
または、findById(ID id)
代わりのより良い代替使用法。
なぜそれほどあいまいなAPIですか?
最後に、Spring-Data-JPA開発者への2つの質問: