Spring data-jpaを使用しています。 1列のみ更新したい。
私のリポジトリは;
public interface UserRepository extends JpaRepository<User,Long> {
}
私のサービスは
public User save(User user) {
return userRepository.save(user);
}
私のエンティティ;
@Entity
@DynamicUpdate(true)
public class User implements Serializable {
// column definitions, etc.
}
User
の1つの列のみを更新するにはどうすればよいですか?
問題は、まったく新しいUser
エンティティを渡すためです。したがって、Hibernateは、データベースから既にフェッチされたキャッシュバージョンを使用できず、動的に更新する列を決定できません。
そのため、以下を実行して @DynamicUpdate
;の正しい動作を確認してください。
稼働中;
@Transactional
public User save(User newUser) {
User currentUser = userRepository.get(newUser.getId());
// handle merging of updated columns onto currentUser manually or via some mapping tool
currentUser.setName(newUser.getName());
return userRepository.save(currentUser);
}
上記のロジックと動的更新アノテーションを使用すると、監査が有効になっていない場合、または@Version
'ed列を使用している場合を除き、name列のみの更新を確認できます。
更新された列が常に同じ場合、updatable = false
の使用は非常に非効率的であるため、@Column
定義の更新の対象ではない列に@DynamicUpdate
を使用することをお勧めしますキャッシュされたSQLを利用せずに、各SQLを新たに生成します。ただし、これらの列をまったく更新できないため、この機能の使用には注意してください。
ネイティブJPA/Hibernateが不十分な場合を除いて、@Query
の使用はお勧めしませんが、列のターゲットセットのみを更新するユースケースがある場合は、それが最良の選択であり、効率的。
更新された列が多く、大きく異なる場合は、newUser
からcurrentUser
への手動マッピングロジックを定義するか、 Orika
などのマッピングツールを使用します。 、私は同様の自動化された構造を持ち、これらのマッパーを介して数百のエンティティにパッチが適用され、非常に汎用的な方法で多くのCRUD操作を処理できます。
まず、_@DynamicUpdate
_が機能しない理由を説明します。したがって、_@DynamicUpdate
_がどのように機能するかに気付くはずです。
@DynamicUpdateアノテーションは、エンティティが変更されるたびにUPDATE SQLステートメントが生成されるように指定するために使用されます。デフォルトでは、Hibernateはすべてのテーブル列を設定するキャッシュされたUPDATEステートメントを使用します。エンティティに@DynamicUpdateアノテーションが付けられている場合、PreparedStatementには値が変更された列のみが含まれます。( 詳細 )
たとえば、User
にname
というプロパティがあると仮定します。
定義された名前で初めてユーザーを保存した場合、値_@DynamicUpdate
_としてnull
を渡すと、変更と見なされ、名前をnull
に更新しようとします。
最初の解決策:
最初の解決策として、_@DynamicUpdate
_が機能するようにしたい場合は、最初に他のすべてのUser
プロパティに古い値を入力してから保存します。
長所:生成されたSQLクエリは、必要なプロパティを更新するだけです。
短所:Hibernateは対応するSQL文字列を毎回生成する必要があるため、Hibernate側のパフォーマンスコストが発生します。
第二の解決策:
カスタム変数でUser
を更新できます:
_@Modifying
@Query("UPDATE User SET name=(:name) WHERE id=(:id)")
public void updateName(@Param("name")String name, @Param("id")Long id);
_
第三の解決策:
最後の解決策として、_updatable = false
_を使用することをお勧めします。これにより、エンティティが挿入された最初の瞬間にプロパティが埋められます。
_ @Column(name = "create_date", nullable = false, updatable = false)
private Instant createDate;
_