0

サード パーティのパスワードをプレーン テキストで格納するデータベース テーブルがありました。現在、暗号化されたパスワードを格納するためにテーブルを更新しています。これを処理するために、@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 にフラッシュするように、エンティティをダーティにするより良い方法はありますか?

リサーチ

4

1 に答える 1