Hibernate 在调用 Setter 时更新数据

Posted

技术标签:

【中文标题】Hibernate 在调用 Setter 时更新数据【英文标题】:Hibernate Updates Data When Calling Setter 【发布时间】:2018-02-17 11:45:16 【问题描述】:

我在数据库中有一个加密值,我想在发送到前端之前对其进行解密。 当我第一次将值保存为加密时,它在数据库中看起来像 -kKwj477382jle34nw。但是,如果我调用我的 getClientByUsername() 函数,我在这个函数中进行解密,当我在将对象发送到前端之前在对象中设置解密值时,数据库中的值也会自动更改。

@Transactional
public ResponseEntity <Client> getClientByUsername(String username) throws Exception 
  Client loggedClient = clientDAO.findByUsername(username);
  String data = loggedClient.getCreditCardNo();
  if (null != data) 
    @SuppressWarnings("static-access")
    byte[] encrypted = base64.decodeBase64(data);
    SecretKeySpec secretKeySpec = new SecretKeySpec(encryptionKey.getBytes(), algorithm);
    Cipher cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    decrypted = cipher.doFinal(encrypted);
    loggedClient.setCreditCardNo(new String(decrypted));
  
  return new ResponseEntity < Client > (loggedClient, HttpStatus.OK);

这是我将值保存为加密的方式:

@Transactional
public boolean clientUpdate(String client) 
    str = updateclient.getCreditCardNo();
    if (null != str) 
      SecretKeySpec secretKeySpec = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), algorithm);
      Cipher cipher = Cipher.getInstance(algorithm);
      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
      encrypted = cipher.doFinal(str.getBytes("UTF-8"));
      updateclient.setCreditCardNo(base64.encodeToString(encrypted));
      return clientDAO.updateProfileClient(updateclient);
    

调用setter时如何阻止hibernate改变值?

更新

@PersistenceContext
private EntityManager entityManager;

public Client findByUsername(String username) throws Exception 
      Query query = entityManager.createNamedQuery("Client.findByUsername");
      query.setParameter("username", username);
      List result = query.getResultList();
      return result.size() > 0 ? (Client) result.get(0) : null;
    

【问题讨论】:

这是一个很好的例子,说明为什么您应该将实体与 dto 分开以进行响应。编辑:以及来自事务逻辑的控制器逻辑 @Zeromus 没有必要。我个人讨厌这种分离,并且总是在项目中与之抗争。 假设它毕竟是一种偏好......但我发现在构建响应时分离逻辑并避免此类问题更加清晰 是的,然后在将属性从一个对象复制到另一个对象时引入大量错误。 【参考方案1】:

你需要在 Hibernate 的会话中 evict 这个对象:

void evict(Object object) throws HibernateException

从会话缓存中删除此实例。对实例的更改 不会与数据库同步。此操作级联到 如果关联被映射,则关联实例 cascade="evict"。

附:只是想,你也可以考虑另一种方法。您可以在 bean 中创建一个字段,将其标记为@Transient,即与数据库解耦,并将其命名为creditCardNoDecrypted。加密字段标记为@JsonIngore(或您用于序列化的任何内容)。

【讨论】:

我相信使用 evict 是更好的方法,但我还没有弄清楚该怎么做 这应该在clientDAO.findByUsername方法中完成 我通过添加findByUsername 函数更新了我的答案。我正在使用EntityManager。我想我需要有hibernate.cfg.xml 才能使用SessionFactory,这是Session 需要的,但我没有。那么entityManager.refresh(obj) 是否与evict(Object obj) 做同样的事情,或者我应该怎么做? 对于 JPA 使用 entityManager.detach(object) 谢谢!它适用于entityManager.detach(object)。我应该阅读什么来了解这些东西?

以上是关于Hibernate 在调用 Setter 时更新数据的主要内容,如果未能解决你的问题,请参考以下文章

useState setter 方法不更新数组

如果实体中没有getter和setter,为啥hibernate不会抛出异常

使用hibernate.get()取得对象再set()属性后调用update()更新对象时一直不能写入到数据库,是啥原因?

为啥在更新事务期间休眠调用删除?

SearchBar 在作为 props 以及来自其父级的 setter 时不会更新值

Hibernate做级联查询时,懒加载的情况下会出现啥异常?