[解決済み] Spring Data JPAでgetOneとfindOneメソッドを使用する場合
質問
以下のように呼び出すユースケースがあります。
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl getUserControlById(Integer id){
return this.userControlRepository.getOne(id);
}
を観察してください。
@Transactional
があります。
伝搬.REQUIRES_NEW
を使用し、リポジトリは
ゲットワン
. アプリを実行すると、次のようなエラーメッセージが表示されます。
Exception in thread "main" org.hibernate.LazyInitializationException:
could not initialize proxy - no Session
...
しかし、もし私が
getOne(id)
で
findOne(id)
はすべて正常に動作します。
ちなみに、ユースケースで getUserControlById メソッドを呼び出した後、すでに insertUserControl メソッド
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl insertUserControl(UserControl userControl) {
return this.userControlRepository.save(userControl);
}
どちらの方式も 伝搬.REQUIRES_NEW をしているので、単純な 監査 の制御を行います。
を使っています。
getOne
メソッドで定義されているからです。
JpaRepository
インターフェイスがあり、私のリポジトリインターフェイスはそこから拡張されています。
その
JpaRepository
インターフェースは
CrudRepository(クラッドレポジトリ
.
また
findOne(id)
メソッドが定義されています。
CrudRepository
.
私の質問です。
-
なぜ
getOne(id)
メソッドを使用できますか? -
を使用する必要があります。
getOne(id)
メソッドを使用できますか?
私は他のリポジトリと一緒に作業していますが、すべてのリポジトリで
getOne(id)
メソッドを使用すると、すべて正常に動作します。
プロパゲーション.REQUIRES_NEW
は失敗します。
によると ゲットワン APIを使用します。
<ブロッククオート指定された識別子を持つエンティティへの参照を返します。
によると FindOne APIを使用します。
<ブロッククオートIDでエンティティを取得する。
-
を使うべき時
findOne(id)
メソッドを使用できますか? -
どのような方法で使用することが推奨されていますか?
解決方法は?
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);
では、1つの
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)
ジャバドック
は、それが:
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)
ジャバドック
の状態です(強調は私)。
を返します。 参照 を、指定された識別子を持つエンティティに変換します。
実際には
参照
という用語がありますが、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 が投げられます。 インスタンス状態に最初にアクセスしたとき . (永続化 プロバイダのランタイムはEntityNotFoundExceptionを投げることが許されています。 が呼び出されたとき、getReference が呼び出されます)。 アプリケーションは インスタンス状態が切り離し時に利用可能になること ただし エンティティ・マネージャが開いている間、アプリケーションによってアクセスされる。
そのため
getOne()
は遅延フェッチされたエンティティを返すかもしれません。
ここでは、遅延フェッチはエンティティのリレーションシップではなく、エンティティそのものを参照しています。
これは、もし私たちが
getOne()
で、Persistenceコンテキストが閉じられると、エンティティはロードされないかもしれないので、結果は本当に予測不可能です。
例えば、プロキシオブジェクトがシリアライズされている場合、そのプロキシオブジェクトに
null
の参照をシリアライズした結果、またはプロキシオブジェクトに対してメソッドを呼び出した場合、次のような例外が発生します。
LazyInitializationException
がスローされます。
ですから、このような状況では、スローの
EntityNotFoundException
を使用する主な理由である
getOne()
は、データベースに存在しないインスタンスを処理するために、エンティティが存在しない間はエラー状況が実行されない可能性があります。
いずれにせよ、セッションを開いている間に、エンティティの読み込みを確実にするために、エンティティを操作する必要があります。これは、エンティティに対して任意のメソッドを呼び出すことで可能です。
または、より良い代替手段を使用する
findById(ID id)
の代わりに
なぜこんなに不明確なAPIなのか?
最後に、Spring-Data-JPAの開発者に2つの質問をします。
-
について、なぜもっと明確なドキュメントがないのでしょうか?
getOne()
? エンティティのレイジーローディングは、本当に細かいことではありません。 -
を導入する必要があるのでしょうか?
getOne()
を包むためにEM.getReference()
?
なぜ、単純にラップ法にこだわらないのか :getReference()
? この EM メソッドは非常に特殊であり、一方getOne()
は、とてもシンプルな処理を伝えています。
関連
-
[解決済み】Spring Data Maven Buildsの「プラグインの実行はライフサイクル構成でカバーされていません」を解決する方法
-
[解決済み] Spring Data JPAにおけるCrudRepositoryとJpaRepositoryのインターフェースの違いは何ですか?
-
原因: org.hibernate.exception.SQLGrammarException: ResultSet を抽出できない エラーの理由
-
[解決済み] JPAの@Entityアノテーションの正確な意味は何ですか?
-
[解決済み] JPA EntityManager。なぜmerge()ではなくpersist()を使うのか?
-
[解決済み] Spring DataでOrderByをfindAllで使用する方法
-
[解決済み] Spring Dataのリポジトリをテストするには?
-
[解決済み] Spring Data JPAでgetOneとfindOneメソッドを使用する場合
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン