Почему я не могу получить открытую сессию JPA для выполнения миграции, когда я использую @Async? - PullRequest
0 голосов
/ 04 февраля 2019

У меня была таблица базы данных, в которой хранились пароли сторонних разработчиков в виде обычного текста.Сейчас я обновляю таблицу для хранения зашифрованных паролей.Чтобы справиться с этим, у меня есть класс @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

1 Ответ

0 голосов
/ 05 февраля 2019

Это потому, что @Transaction не учитывается, когда вы вызываете метод из компонента внутри (и используете стандартный AOP) механизм.Более подробный ответ здесь: https://stackoverflow.com/a/4396530/66686

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...