2013-10-02 4 views
0

Я использую реализацию Hibernate JPA 2.0 для создания счетчика в строке таблицы. Я использую MySQL 5.5 с движком InnoDB. Я пытаюсь заблокировать строку счетчика, чтобы никакие процессы вне JVM не могли видеть этот счетчик, пока мой код не увеличит его. Мой код выглядит следующим образом:Hibernate JPA - PESSIMISTIC.WRITE не работает

//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(), чтобы приостановить код в середине сделки. Пока поток спал, я использую клиент CLI MySQL для входа в базу данных и проверки значения свойства. Эта сессия выглядит примерно так:

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

[email protected] [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?

ответ

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/, которые не требуют какой-либо замок.

Смежные вопросы