Hibernate JPA - PESSIMISTIC.WRITE 不工作

Posted

技术标签:

【中文标题】Hibernate JPA - PESSIMISTIC.WRITE 不工作【英文标题】:Hibernate JPA - PESSIMISTIC.WRITE not working 【发布时间】:2013-10-02 22:19:29 【问题描述】:

我正在使用 JPA 2.0 的 Hibernate 实现在表行中创建一个计数器。我正在使用带有 InnoDB 引擎的 mysql 5.5。我正在尝试锁定计数器行,以便 JVM 之外的任何进程都无法查看该计数器,直到我的代码将其递增。我的代码如下所示:

  //inside a Transaction....

  //key is an enum
  final PropertyKey key = PropertyKey.DEPLOY_COUNTER;
  final Query query =
     entityManager.createQuery("FROM Property s where propertyKey = :key").setParameter("key", key);
  query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
  LOG.debug("Blocking (maybe) while waiting to update deploy counter");
  final Property counterAsProperty = (Property) query.getSingleResult();

  try
  
     Thread.sleep(15000);
     //while sleeping I use MySQL cli to check value of property in database
  
  catch (InterruptedException e)
  
     e.printStackTrace();
  

  //in java, increment counter by one and then save in db
  //...

我使用 Thread.sleep() 在事务中间暂停代码。当线程处于休眠状态时,我使用 MySQL CLI 客户端登录到数据库并检查属性的值。该会话看起来像这样:

user@mypc [user]> begin work;
Query OK, 0 rows affected (0.00 sec)

user@mypc [user]> select * from property where property_key = 'DEPLOY_COUNTER';
+----+---------+-----------+--------------------+----------------+
| id | version | encrypted | property_key       | property_value |
+----+---------+-----------+--------------------+----------------+
| 10 |       0 |         0 | DEPLOY_COUNTER     | 66             |   
+----+---------+-----------+--------------------+----------------+

请注意查询是如何立即返回的(0.00 秒),因为我预计它会阻塞,直到线程退出睡眠并且事务完成。我对 LockModeType.PESSIMISTIC_WRITE 的理解是,它应该把检索到的行放在一个独占锁中,不能被另一个事务读取或写入。

注意:当线程处于休眠状态时,对此行的更新确实会阻塞。

如果我设置了 PESSIMISTIC_WRITE 锁定模式,为什么另一个 DB 连接可以在另一个事务正在运行时查看数据?

【问题讨论】:

【参考方案1】:

默认的 InnoDB 隔离级别是 REPEATABLE READ,它允许没有排他锁的事务读取(但不更新)锁定的记录。这允许其他事务对记录进行非脏读。 SERIALIZABLE 似乎可以防止对锁定记录的任何读取。您可以在使用hibernate.connection.isolation 设置休眠连接属性时设置隔离级别,尽管这会影响所有连接,而不是我愿意支付的成本。这篇 SO 帖子指出了一种按连接执行此操作的方法,但该方法需要不推荐使用的方法:JPA and MySQL transaction isolation level

我最终使用了其中一个

UPDATE counter SET value = LAST_INSERT_ID(value + 1);
SELECT LAST_INSERT_ID();

此处引用的方法:http://tedyoung.me/2011/04/14/jpa-counters-and-sequences/,不需要任何锁定。

【讨论】:

【参考方案2】:

对于选择查询,这不起作用

如果您查询“选择更新”,它将起作用 那么您的查询将等到您的应用程序不释放锁定的时间

select * from property where property_key = 'DEPLOY_COUNTER' for update;

上面的查询会一直等到锁被释放。

【讨论】:

以上是关于Hibernate JPA - PESSIMISTIC.WRITE 不工作的主要内容,如果未能解决你的问题,请参考以下文章

spring.jpa.hibernate.hbm2ddl 和 spring.jpa.hibernate.ddl 之间的区别

JPA和Hibernate的关系

Spring Hibernate JPA 联表查询

Spring Hibernate JPA 联表查询 复杂查询

JPA 等同于 Hibernate org.hibernate.criterion.Example?

Hibernate JPA 的异常