質問: * 私のプロジェクトでも`save`しか使っておりません。そしてDBにデータが反映されることを確認しています。`saveAndFlash`を使うことは必要なのでしょうか? * リポジトリーの実装によって挙動が変わってきそうな内容ですね。私はHibernateを使っています。英語の記事だとメモリにデータがあるのでフラッシュしないとDB反映されなさそうですが、私の環境では `save` のみでDB反映されています。なぜでしょうか? * `EntityManager.flush()`はすべてのSQLを実行するとありますが、私は`save`のみしか使っていないので「すべて」がどういうことで何を示すのかわかりません。具体的な例がありましたら知りたいです。
回答: Hibernateにおいて、`save`と`flush`は次のようなニュアンスです。 * `save`: ユーザが生成したエンティティをHibernate管理下に置く(=永続化対象にする) * `flush`: Hibernateが管理している状態をDBに書き出し、管理している状態とDBが保持する情報を同期させる。要は実際にSQLを実行する。 ユーザが参照するのHibernateが管理している状態であり、DBの状態は原則的には気にする必要がありません。 なので`flush`を使う機会がない、というのは普通です。 ユーザが明示的に`flush`を行わずとも、必要に応じて(例: トランザクションcommit時に)Hibernateは管理している状態をDBに反映させます。 Hibernateのリファレンスの次の章が該当します: * 5. Persistence Context + エンティの状態を transient から managed にするメソッドがHibernateの`save`です(Spring Data JPAの`save`は`merge`も一緒くたになっていますが) * 6. Flushing > > * 私のプロジェクトでもsaveしか使っておりません。そしてDBにデータが反映されることを確認しています。saveAndFlashを使うことは必要なのでしょうか? > > > パフォーマンス低下防止を目的として、一度に多量のSQLを実行せずに済むように`flush`を挟む、みたいな用途が最も有り得そうかなと思います。 また、ユーザがDBへの反映タイミングを制御したい場合にも必要になるかもしれません。 例えばトラクション分離レベルが関わってくる話だとDBのデータを更新したのかどうかは気にする必要があるでしょう。 私の経験としては、監査記録としてDBのSQLログを用いるため特定のタイミングではSQL文を必ず実行したい、という要求を実現するため`flush`を用いていたようなものもありました。 > > * リポジトリーの実装によって挙動が変わってきそうな内容ですね。私はHibernateを使っています。英語の記事だとメモリにデータがあるのでフラッシュしないとDB反映されなさそうですが、私の環境では save のみでDB反映されています。なぜでしょうか? > > > `flush`を行うとそのタイミングでSQLが実行されますが、`flush`を行わずともいずれはSQLが実行されます。 なので、フラッシュしないとDB反映されない、というのはそのタイミングではそうかもしれませんが、長期的(例えばトランザクション終了後)まで考えると正しくありません。いずれは反映されます。 > > * EntityManager.flush()はすべてのSQLを実行するとありますが、私はsaveのみしか使っていないので「すべて」がどういうことで何を示すのかわかりません。具体的な例がありましたら知りたいです。 > > > 例えば次のようなコードの場合、`saveAndFlush`を`save`に変えると、`INERT`も`UPDATE`も実行されません(※Flusing mode: `AUTO`の場合): ``` @Transactional public String method() { final MyEntity e = new MyEntity(); final MyEntity p = repository.saveAndFlush(e); p.setName("renamed"); repository.saveAndFlush(p); throw new RuntimeException(); // rollback } ``` (以下、根拠のない私の想像ですが) `saveAndFlush`というメソッドは、おそらく、「`save`メソッドを呼んだらSQLが実行されれてDBが更新されると思ったのにされないんですけど...!?」というSpring Data JPAユーザの頻出疑問に応えるためのお節介メソッドです。 なので、`save`で事足りているのであれば`saveAndFlush`については存在を気にする必要は無いと思います。 そもそも、`save`は引数で指定した特定のエンティティをターゲットにするのに対し、`flush`はHibernate管理エンティティ全てがターゲットなので、いつでも`saveAndFlush`として一緒くたにまとめてしまって良いわけでも無いです。