【问题标题】:Reattaching a detached instance: hibernate lock()重新附加一个分离的实例:hibernate lock()
【发布时间】:2015-02-27 14:40:05
【问题描述】:

我有点困惑。我不明白为什么 lock()/buildLockRequest() 之前所做的更改会传播到数据库。

在此示例中,我设置了初始价格,不应将其更新到数据库中。但如果我把它打印出来,它实际上已经更新了。还是事情发生了变化?本书使用的是 Hibernate 3,而我使用的是 Hibernate v3.6.10。

Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

Item item = (Item) session.get(Item.class, new Long(1));

tx.commit();
session.close();

Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
Transaction tx2 = sessionTwo.beginTransaction();
// Changes made before the call to lock() aren’t propagated to the database
item.setInitialPrice(new BigDecimal(179));

// sessionTwo.lock(item, LockMode.NONE);
sessionTwo.buildLockRequest(LockOptions.NONE).lock(item);
item.setDescription("This playstation 3 is in a fine state");
GregorianCalendar gc = new GregorianCalendar();
gc.setLenient(false);
gc.set(2015, 0, 31, 9, 12, 34);

item.setEndDate(gc.getTime());

item = (Item) sessionTwo.get(Item.class, new Long(1));

tx2.commit();
sessionTwo.close();

logger.debug(item.toString()); // still changes are made to initialPrice property

来自Java Persistence With Hibernate

在这种情况下,确实在对象之前或之后进行更改 被重新连接。在调用 lock() 之前所做的更改不会传播到 数据库,只有在确定分离的实例没有被删除时才使用它 修改的。此方法仅保证对象的状态从 分离到持久化,Hibernate 将再次管理持久化对象。 当然,一旦对象处于托管持久状态,您对它所做的任何修改 状态需要更新数据库。 我们将在下一章讨论 Hibernate 锁定模式。通过指定锁定- Mode.NONE 在这里,你告诉 Hibernate 不要执行版本检查或获取任何 将对象与 Session 重新关联时的数据库级锁。如果您指定 LockMode.READ 或 LockMode.UPGRADE,Hibernate 将执行 SELECT 语句以执行版本检查(并锁定数据库中的行) 用于更新)。

【问题讨论】:

  • 不应该是sessionTwo.buildLockRequest(LockOptions.NONE).lock(item);吗?
  • 是的,忘记了。这本书正在使用已弃用的方法 lock()。
  • 您是否尝试在调试器中单步执行您的代码?告诉 hibernate 输出 SQL 语句,这样您就可以看到更改写入数据库的时间。
  • 我打开了hibernate.show_sql。它会进行选择,而不仅仅是在事务提交时进行更新。 InitialPrice 不应更新。我修改了这本书的例子,看看它是否确实如此。所以 lock() 重新附加了分离的对象,但是为什么书中说在锁定之前所做的更改不会传播,但在这种情况下它会传播。

标签: java hibernate jpa transactions locking


【解决方案1】:
//Changes made before the call to lock() aren’t propagated to the database
item.setInitialPrice(new BigDecimal(179));

这是预期的行为,因为项目对象已分离,并且已分离的对象不受automatic dirty checking 的约束,因此在此特定状态下不会将更改传播到数据库。

重新连接后:

sessionTwo.buildLockRequest(LockOptions.NONE).lock(item);

脏检查将在刷新时应用。当您重新附加实体时,Hibernate 会发出一个 SQL SELECT 以获取最新的实体状态,该状态将在刷新时用于将其与内存中的对象数据进行比较。

这就是为什么在锁定之后(即使是 LockOptions.NONE),您会看到更改传播。

如果您注释锁定方法,则不会传播任何更改,因为第二个会话 不知道分离的项目。

【讨论】:

  • 我明白了。感谢您的澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-14
  • 2010-10-29
  • 1970-01-01
相关资源
最近更新 更多