如何改变Hibernate的自动持久策略

时间:2010-05-21 20:00:13

标签: hibernate jpa setter

我刚刚注意到在调用任何save()update()方法之前,Hibernate实体会自动持久保存到数据库(或至少是缓存)。对我来说,这是一个非常奇怪的默认行为 - 但是好的,只要我可以禁用它,就可以了。

我遇到的问题是我想更新我的实体的状态(从状态“1”到状态“2”)只有当数据库中的实体仍然具有我检索它时的状态时(状态“1”) “)。这是为了消除另一台服务器更新同一对象时的并发问题。出于这个原因,我创建了一个自定义NamedQuery,它只会在实体处于预期状态“1”时更新它。这是一些伪代码:

// Get the entity
Entity item = dao.getEntity(); 
item.getState(); // == 1

// Update the entity
item.setState(2); // Here is the problem, this effectively changes the
                  // state of my entity breaking my query that verifies
                  // that state is still == 1.

dao.customUpdate(item); //Returns 0 rows changes since state != 1.

如何确保setter不更改cache / db中的状态?

2 个答案:

答案 0 :(得分:1)

Hibernate内置了对您要实现的目标的支持 - 它支持使用版本ID或时间戳进行乐观锁定。如果您尝试保存对象并且基础数据已更改,则hibernate会抛出异常。您可以捕获此异常并根据需要进行处理 - 忽略更新,重试或任何有意义的事情。

请参阅Optimistic Concurrency Control

编辑:我不清楚你的更新查询是如何工作的,但如果你想继续这样做,你可以在撤回之后从会话中驱逐你的对象。这将为您提供对象的快照,因为它可以在检索时独立于db / cache进行修改。您可以将其作为比较的一方传递到自定义更新查询中,另一方是持久值。当查询选择/更新实体时,它将从数据库中重新读取,而不是从被驱逐的对象中读取。然后,您的更新查询可以将其与您的驱逐/修改值(作为参数传递)进行比较,以查看是否应该进行更新。

请参阅Session.evict()

答案 1 :(得分:0)

您应该设置会话的刷新模式。这样会话实体只会在执行session#flush()之后保持不变;

如果您希望更新会话缓存或数据库,请执行以下操作:

Bean bean = session.get(Bean.class, bean.getId());
session.setFlushMode(FlushMode.COMMIT);
// Make some changes to bean object.
Bean bean2 = session.get(Bean.class, bean.getId());
Assert.assertFalse(bean.equals(bean1)); // Assuming equals and hashcode are implemented