サード パーティのパスワードをプレーン テキストで格納するデータベース テーブルがありました。現在、暗号化されたパスワードを格納するためにテーブルを更新しています。これを処理するために、@EntityListener
ロード後の暗号化と復号化、および永続化/更新前の暗号化と復号化を行うクラスがあります。現在、データベースに現在あるすべてのパスワードを暗号化するコードを作成しようとしています。
移行されていないすべてのものをロードして再度保存する移行関数を作成しました (エンティティ リスナーを実行できるようにするため)。オブジェクトがダーティであると Hibernate が判断しない限り、エンティティ リスナーは実際には呼び出されないため、変換を実行する最も簡単な方法であると考えて、現在のセッションからエンティティを削除することにしました。ここに私が持っているものがあります:
public class Migrator {
@Autowired
EntityManager entityManager;
@Autowired
MyRepository myRepo;
@Async
public void migrateAll() {
List<MyEntity> toBeMigrated = myRepo.getUnencrypted();
for (MyEntity eachEntity : toBeMigrated) {
attemptEncryption(eachEntity);
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void attemptEncryption(MyEntity entity) {
Session session = (Session) entityManager.getDelegate();
session.evict(entity);
myRepo.save(entity);
}
}
(表示されていません: Migrator を呼び出す単純な Web コントローラー)
移行された各レコードが保存されるように、@Transactional
注釈を追加しました。attemptEncryption()
操作全体のロールバックを引き起こすランダムな行での失敗は望ましくありませんでした。何かが正常に保存されたらすぐに、そのトランザクションをコミットしたいと思います。
これは実行に時間がかかるため、HTTP 応答を送り返し、migrateAll()
別のスレッドで実行したいと考えました。マルチスレッドなしで問題なく動作しましたが、@Async
注釈を追加するorg.hibernate.SessionException: Session is closed!
と、例外が発生しました (スタックトレースは、エンティティを削除しようとしたときに例外がスローされたことを示しましたattemptEncryption()
)。作業を別のスレッドに移動したことが原因だと思い@Async
ますが、アプリケーションの他の部分で問題なく使用しました。このコードと私の他の非同期コードの唯一の大きな違いは、セッションからエンティティを削除していることです。他ではやってません。また、データベースはエンティティを適切にロードしますmyRepo.getUnencrypted()
。Hibernateで何か間違ったことをしていた場合、これは失敗するはずだと思います。
質問
- エンティティを削除しようとすると、セッションが閉じられるのはなぜですか?
- Hibernate が pre-persist リスナーを実行して DB にフラッシュするように、エンティティをダーティにするより良い方法はありますか?
リサーチ
- (デタッチされたオブジェクトのロード) Spring Data JPA と JPA EntityListener を使用したフィールド レベルの暗号化- メソッドに追加しようとし
@Transactional(propagation = Propagation.NOT_SUPPORTED)
ましgetUnencrypted()
たが、何も変わりませんでした。 - (@Async メソッドのセッション) https://stackoverflow.com/a/29271930/2047962 -
@Transactional
規定どおりに既に注釈を使用しています。 - (「クリーンな」エンティティの更新を強制する) https://stackoverflow.com/a/37255257/2047962 - Persistable を使用できません。このエンティティが常に汚れているように見えるのは望ましくありません。この 1 つのメソッドのために汚れているだけです。
- Hibernate での強制更新- このコードを
attemptEncryption()