为什么我不能得到一个开放的JPA会话,当我使用@Async做迁移作业?

问题描述 投票:0回答:1

我不得不说是采用明文存储第三方密码的数据库表。我现在更新表来存储加密的密码。为了解决这个问题,我有一个@EntityListener的类,它的加密和解密后的负荷和预坚持/更新。现在,我想编写代码来加密所有当前在数据库中的密码。

我写的迁移功能加载尚未迁移的一切,再次保存(使实体监听器可以运行)。实体监听器实际上不会被调用,除非休眠认为对象是脏的,所以我决定从当前会话驱逐实体,以为这将是运行转换的最简单方法。下面是我有:

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);
  }
}

(未示出:一个简单的web控制器调用迁移程序)

我加入了@Transactional注释attemptEncryption()使每个迁移记录将被保存。我不想在一个随机行导致整个操作回滚失败;只要东西保存成功,我想该交易提交。

由于这需要一段时间的运行,我想送回HTTP响应,并在一个单独的线程中运行migrateAll()。它工作得很好不用多线程,但是一旦我添加了注释@Async,我结束了org.hibernate.SessionException: Session is closed!异常(堆栈跟踪表明,试图驱逐在attemptEncryption()实体时抛出异常)。我认为移动工作到另一个线程是原因,但我已经在我的应用程序的其他部分使用@Async没有任何问题。此代码,我的其他异步代码之间唯一的主要区别是,我从赶出会议实体;我不这样做,其他地方。此外,数据库加载实体只是myRepo.getUnencrypted()罚款。我喜欢这种感觉好像我做错事与Hibernate应该失败。

Questions

  • 为什么当我去驱逐实体我的会议结束?
  • 有没有更好的办法让我的实体脏,使Hibernate会运行前一直存在侦听器,并刷新到数据库?

Research

hibernate spring-data-jpa spring-async
1个回答
0
投票

这是因为@Transaction未考虑当你调用从内豆的方法(和使用标准AOP)机制。更详细的答案就在这里:https://stackoverflow.com/a/4396530/66686

© www.soinside.com 2019 - 2024. All rights reserved.