0

我正在使用 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 锁定模式,为什么另一个数据库连接可以在另一个事务正在运行时查看数据?

4

2 回答 2

1

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

我最后使用了其中一个

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

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

于 2013-10-06T18:18:56.967 回答
0

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

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

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

上面的查询将等到锁被释放。

于 2021-03-03T19:44:24.287 回答