我有一个从数据库中获取数据的服务,该数据库具有以加密值存储的列。

从DAO中获取后,我将把属性的值更新为解密后的值,然后将其作为API的响应发送。

我认为该实体已为选择查询启用了更改跟踪,这也是因为获取数据后,将使用解密的密码在数据库中更新数据。我已经搜寻了一下,发现使用EntityManager解决了问题,但是对于此实现,我必须在许多实体中进行很多代码更改。

从这个链接,我看到我们必须编写自定义的无状态bean并注入代码,但是看起来不正确。请向我建议解决此问题的最佳方法。

我的DAO:

@Repository
public interface EnvironmentDao extends JpaRepository<Environment, Long> {


//自定义方法与本地查询一起使用
}

我的服务

@Override
    public List<Environment> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
        if (environmentIds == null || environmentIds.size() < 1) {
            return null;
        }

        return decryptPassword(environmentDao.findAllById(environmentIds));
    }


在cryptoPassword方法内部,我只是遍历所有记录,然后设置解密密码,例如

e.setDB_Password(encryptionService.decrypt(e.getDB_Password()));


我昨天注意到的一个案例是,对于任何错误的类似实体,都有一个数据库保存,并且该值得到了更新,因此,在更正错误之后,此更改就没有发生。

请帮助我,因为我不是Java方面的专家,并且需要花费更多时间进行分析并且无法理解。在C#的情况下,我会使用.AsNoTracking(),但是我对Java的了解并不多,而且四处游荡。

在服务中尝试了以下内容

@Autowired
EntityManager entityManager;


在方法中

Optional<Environment> environment = environmentDao.findById(id);
entityManager.detach(environment.get());
return managePassword(environment.get(), false);

最佳答案

我建议两种选择来克服无意中更新的实体:


我建议不要创建实体DTO类并创建该类的实例,然后将相关属性设置到DTO实例上,而不是返回实体本身,这样就不会对实体本身进行任何更改。因此,代码将如下所示:


public List<EnvironmentDTO> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
  if (environmentIds == null || environmentIds.size() < 1) {
      return null;
  }

  return createEnvironmentDTOs(environmentDao.findAllById(environmentIds));
}

private LisT<EnvironmentDTO> createEnvironmentDTOs(List<Environment> environments) {
  return environments.stream().map((env) -> {
    EnvironmentDTO envDto = new EnvironmentDTO();
    // Copy all relevant fields to DTO (you can even use some Mapper library for this, i.e. http://modelmapper.org/)
    envDto.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
  })
}



如果您想返回实体,无论如何,而不是从实体创建DTO类和实例;您可以分离实体,以便对实体所做的更改不会反映到数据库中。因此,解密密码并将其设置回实体后,您需要做的是detaching实体:entityManager.detach(environment)

10-01 03:02
查看更多