2013-10-09 1 views
4

Я пытаюсь использовать пессимистическую блокировку в JPA, над Hibernate 3 против базы данных Postgres. Я не могу заставить замок тайм-аут - кажется, что он вечно вешает.JPA Пессимистическая попытка блокировки никогда не вылетает

Вот пример:

EntityManagerFactory factory; 

// (initialise the factory) 

EntityManager em1 = factory.createEntityManager(); 
EntityManager em2 = factory.createEntityManager(); 

// em1 gets a lock 

EntityTransaction transaction1 = em1.getTransaction(); 
transaction1.begin(); 
MyObject object1 = em1.find(MyObject.class, 1, LockModeType.PESSIMISTIC_READ); 

// em2 tries for a lock 

Map<String,Object> timeoutProperties = new HashMap<String,Object>(); 
timeoutProperties.put("javax.persistence.lock.timeout", 5000); 

EntityTransaction transaction2 = em2.getTransaction(); 
transaction2.begin(); 
MyObject object2 = em2.find(MyObject.class, 1, LockModeType.PESSIMISTIC_READ, timeoutProperties); 

// After five seconds I expect em2 to bail out, but it never does. 

transaction1.rollback(); 
transaction2.rollback(); 

Как я понимаю, em2 должен был попытаться до пяти секунд (5000 мс), чтобы получить блокировку, а затем должен был выброшен исключение. Вместо этого код блокируется.

Если я запускаю это в двух разных потоках, то вижу, что thread2 (с em2) получает блокировку, как только thread1 (em1) освобождает ее. Таким образом, блокировка происходит, просто не сглаживается.

я получить тот же эффект с PESSIMISTIC_WRITE, и с любым значением таймаута (2мс, 0ms 'NO WAIT') и т.д.

Я использую Hibernate 3.6.10 Final (последняя версия Hibernate 3) и Postgres Драйвер jdbc 9.2-1003.jdbc4 (последний драйвер). Я бегу против базы данных Postgres 8.4.

Вся документация, которую я нашел, предполагает, что это должно работать. Есть идеи?

спасибо, Аластер

ответ

5

Postgres SELECT для синтаксиса обновлений предоставляет только опции, чтобы не дождаться, если блокировка не будет получена сразу. См. Документы postgres.

Чтобы предотвратить операцию, ожидающую выполнения других транзакций с фиксацией , используйте параметр NOWAIT. С помощью команды NOWAIT оператор сообщает ошибку , вместо того, чтобы ждать, если выбранная строка не может быть заблокирована немедленно. Обратите внимание, что NOWAIT применяется только к блокировкам уровня строки - . Необходимая блокировка уровня ROW SHARE по-прежнему выполняется обычным способом (см. Главу 13). Сначала вы можете использовать LOCK с опцией NOWAIT, , если вам нужно приобрести блокировку на уровне таблицы без ожидания.

При работе с Postgres я заметил, что любое значение больше 0 для тайм-аута будет вызывать спящий режим выдавать SELECT FOR UPDATE но когда таймаут 0 будет выдавать SELECT FOR UPDATE NO WAIT

+0

Хотя я не ожидал ответа, это похоже на то, что я видел - спасибо! – Alastair

+1

Если вы не установите javax.persistence.lock.timeout в ноль в файле свойств, запрос выполняется только с «FOR UPDATE». Если вы установите его на ноль (как я уже сказал), выполняется «ЗАВЕРШЕНИЕ ОБНОВЛЕНИЯ». –

+0

По крайней мере, в Hibernate 4.3.x & JPA 2.1 вы можете указать эти параметры на уровне запроса. Как в @NamedQuery (через свойство hints), так и в запросе, созданном через entityManager.createQuery (CriteriaBuilder.createQuery (Entity ...)), используя setHint (...). – gkephorus

0

Поместите это в persistence.xml:

<property name="javax.persistence.lock.timeout" value="0"/> 

Или установить свойство перед вызовом первой блокировки.

+0

Привет Márcio, спасибо, но это не имеет никакого значения ни как переменную persistence.xml или как свойство для первой блокировки. – Alastair