有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Hibernate JPA悲观。写不起作用

我正在使用JPA2.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
  //...

我用线。SLIP()在事务中间暂停代码。当线程处于睡眠状态时,我使用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的理解。悲观的_WRITE是,它应该将检索到的行置于独占锁中,不可由另一个事务读取或写入

注意:当线程处于睡眠状态时,不会阻止对此行的更新

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


共 (2) 个答案

  1. # 1 楼答案

    对于select查询,这不起作用

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

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

    上面的查询将等待锁被释放

  2. # 2 楼答案

    默认的InnoDB隔离级别是REPEATABLE READ,它允许没有独占锁的事务读取(但不更新)锁定的记录。这允许其他事务对记录进行非脏读。SERIALIZABLE可防止对锁定记录进行任何读取。您可以在使用hibernate.connection.isolation设置hibernate连接属性时设置隔离级别,尽管这会影响所有连接,而不是我愿意支付的成本。这篇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/,不需要任何锁定