превышено время ожидания блокировки гибернации; - PullRequest
9 голосов
/ 24 декабря 2009

Я использую Hibernate, пытаюсь смоделировать 2 одновременных обновления одной и той же строки в базе данных.

Редактировать: я переместил em1.getTransaction (). Commit сразу после em1.flush (); Я не получаю никакого StaleObjectException, две транзакции успешно завершены.

Session em1=Manager.sessionFactory.openSession();
Session em2=Manager.sessionFactory.openSession();

em1.getTransaction().begin();
em2.getTransaction().begin();

UserAccount c1 = (UserAccount)em1.get( UserAccount.class, "root" );
UserAccount c2 = (UserAccount)em2.get( UserAccount.class, "root" );

c1.setBalance( c1.getBalance() -1 );
em1.flush();
System.out.println("balance1 is "+c2.getBalance());
c2.setBalance( c2.getBalance() -1 );
em2.flush(); // fail

em1.getTransaction().commit();
em2.getTransaction().commit();

System.out.println("balance2 is "+c2.getBalance());

Я получил следующее исключение на em2.flush(). Почему?

2009-12-23 21:48:37,648  WARN JDBCExceptionReporter:100 - SQL Error: 1205, SQLState: 41000
2009-12-23 21:48:37,649 ERROR JDBCExceptionReporter:101 - Lock wait timeout exceeded; try restarting transaction
2009-12-23 21:48:37,650 ERROR AbstractFlushingEventListener:324 - Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.persister.entity.AbstractEntityPersister.processGeneratedProperties(AbstractEntityPersister.java:3702)
    at org.hibernate.persister.entity.AbstractEntityPersister.processUpdateGeneratedProperties(AbstractEntityPersister.java:3691)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:147)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
    at com.ch.whoisserver.test.StressTest.main(StressTest.java:54)
Caused by: java.sql.BatchUpdateException: Lock wait timeout exceeded; try restarting transaction
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1213)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:912)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    ... 10 more

1 Ответ

21 голосов
/ 24 декабря 2009

Ну, вы пытаетесь зайти в тупик и у вас все получается: -)

  1. Transaction1 запускается, обновляет (и блокирует) строку с вашей сущностью.
  2. Transaction2 пытается сделать то же самое, но не может, потому что строка все еще заблокирована. Таким образом, он ожидает (и ждет, и ждет), пока тайм-аут не будет превышен

Реальная * симуляция будет иметь 1-го и 2-го менеджера сущностей плюс соответствующие обновления / транзакции в отдельных потоках. Таким образом, вы получите:

  1. Transaction1 запускается, обновляет (и блокирует) строку с вашей сущностью.
  2. Transaction2 пытается сделать то же самое, но не может, потому что строка все еще заблокирована. Так что он ждет (и ждет, и ждет) ...
  3. Тем временем Transaction1 фиксируется и блокировка снята
  4. Транзакция2 теперь может продолжаться

Обратите внимание, что в этот момент (# 4 выше) вы будете перезаписывать изменения, сделанные Transaction1. Hibernate может использовать оптимистическую блокировку , а также пессимистическую блокировку , чтобы предотвратить это.

Обновление (на основе комментариев):

Если сущность имеет версию, Transaction2 (# 4 выше) завершится ошибкой. Тем не менее, ваш опубликованный код не достигает этой точки, потому что Transaction2 не может получить блокировку, как описано выше. Если вы хотите специально проверить, что оптимистическое управление версиями работает, вы можете сделать следующее:

  1. Получить em1, начать транзакцию, получить вашу сущность, совершить транзакцию, закрыть em1.
  2. Получить em2, начать транзакцию, получить вашу сущность, обновить вашу сущность, зафиксировать транзакцию, закрыть em2.
  3. Получите em3, запустите транзакцию, попробуйте обновить сущность, загруженную на шаге 1 - тест не пройдёт здесь.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...