我不得不说是采用明文存储第三方密码的数据库表。我现在更新表来存储加密的密码。为了解决这个问题,我有一个@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应该失败。
@Transactional(propagation = Propagation.NOT_SUPPORTED)
到getUnencrypted()
方法,但什么都没有改变。@Transactional
注解规定。attemptEncryption()
验证码这是因为@Transaction
未考虑当你调用从内豆的方法(和使用标准AOP)机制。更详细的答案就在这里:https://stackoverflow.com/a/4396530/66686