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 ロック モードを設定した場合、他のトランザクションが実行されているときに別の DB 接続がデータを表示できるのはなぜですか?

4

2 に答える 2

1

デフォルトの InnoDB 分離レベルは REPEATABLE READ です。これにより、排他ロックのないトランザクションがロックされたレコードを読み取ることができます (更新はできません)。これにより、他のトランザクションがレコードに対してダーティでない読み取りを実行できるようになりました。SERIALIZABLE は、ロックされたレコードの読み取りを防止するように見えます。hibernate.connection.isolationを使用して休止状態の接続プロパティを設定するときに分離レベルを設定できますが、これはすべての接続に影響しますが、私が支払うつもりだったコストではありません。この SO 投稿は、接続ごとにそれを行う方法を示していますが、このアプローチには非推奨の方法が必要です: JPA および MySQL トランザクション分離レベル

私はそのうちの1つを使用して巻き上げました

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 に答える