У меня была таблица базы данных, в которой хранились пароли сторонних разработчиков в виде обычного текста.Сейчас я обновляю таблицу для хранения зашифрованных паролей.Чтобы справиться с этим, у меня есть класс @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)
Я добавил аннотацию @Transactional
к attemptEncryption()
, чтобы каждая перенесенная запись моглабыть спасеннымЯ не хотел, чтобы сбой в случайной строке вызывал откат всей операции;как только что-то будет успешно сохранено, я хочу, чтобы эта транзакция была зафиксирована.
Поскольку для запуска требуется некоторое время, я хотел отправить обратно HTTP-ответ и запустить migrateAll()
в отдельном потоке.Он работал нормально без многопоточности, но как только я добавил аннотацию @Async
, у меня возникли исключения org.hibernate.SessionException: Session is closed!
(трассировка стека показала, что исключение возникло при попытке выселить сущность в attemptEncryption()
).Я предполагаю, что причиной является перенос работы в другой поток, но я использовал @Async
в других частях моего приложения без каких-либо проблем.Единственное существенное различие между этим кодом и другим моим асинхронным кодом состоит в том, что я исключаю сущности из сеанса;Я больше этим не занимаюсь.Кроме того, база данных прекрасно загружает объекты с помощью myRepo.getUnencrypted()
.Я чувствую, что это не получится, если я что-то не так с Hibernate.
Вопросы
- Почему моя сессия закрывается, когда я иду, чтобы выселить сущность?
- Есть ли лучший способ сделать мою сущность грязной, чтобы Hibernate запустил прослушиватель pre-persist и сбросил его в БД?
Research