JPA 1.0 и Hibernate 3.4 генерируют FOR UPDATE NOWAIT при блокировке - PullRequest
3 голосов
/ 19 мая 2011

В настоящее время я работаю над проектом Java EJB, развертываемым в Weblogic 10.3.3. Мы используем JPA 1.0 с Hibernate 3.4 в качестве разработчика. Мы также используем Oracle10g Dialect.

Проблема, с которой мы сталкиваемся, связана с генерацией SQL в спящем режиме при попытке заблокировать строку для обновления.

Мы выполняем запрос:

Query q = entityManager.createNamedQuery("findMyObject");    
MyHibernateObject myObject= (MyHibernateObject ) q.getSingleResult();

А затем заблокируйте этот объект с помощью:

entityManager.lock(myObject, LockModeType.WRITE);

Этот акт блокировки генерирует запрос:

SELECT myObject FROM myTable FOR UPDATE NOWAIT

Я хочу, чтобы он сгенерировал:

SELECT myObject FROM myTable FOR UPDATE

Разрешение другим потокам запрашивать этот объект без исключения: org.hibernate.exception.LockAcquisitionException и просто ждать своей очереди или позволить тайм-ауту транзакции EJB.

Итак, зная все это, могу ли я заставить Hibernate генерировать SQL без ключевого слова NOWAIT?

Я знаю, что использование Hibernate 3.6 и JPA 2.0 позволит это использовать пессимистичную блокировку, но из-за того, что Weblogic поддерживает только JPA 1.0, наши руки связаны.

В идеале я хочу избежать написания нашего собственного механизма повтора и / или тайм-аута, обрабатывая исключение, когда все, что мне нужно, это просто увеличить SQL, который генерирует Hibernate, когда EntityManager создает блокировку.

Ответы [ 2 ]

6 голосов
/ 20 мая 2011

Хорошо, мы используем обходной путь до тех пор, пока не обновим Weblogic до 10.3.4

Вот если кто-то еще наткнется на это:

SessionImpl session = (SessionImpl)entityManager.getDelegate();
session.lock(myObject, LockMode.UPGRADE);

Это, конечно, выходит изСтандарт JPA, в котором мы представляем реализацию спящего режима и используем сеанс спящего режима.

Но он будет генерировать

SELECT myObject FOR UPDATE

вместо

SELECT myObject FOR UPDATE NOWAIT

Надеюсь, это поможеткто-то.

0 голосов
/ 14 июля 2019

Используйте код ниже, чтобы пропустить заблокированную строку.Это альтернатива

select * from student, где идентификатор студента = n для обновления nowait

Метод findStudnt выдает ошибку, если строка уже заблокирована.Если нет ошибки, вызовите метод updateStudent для обновления сущности студента, иначе запишите ошибку для аудита.

@Override
public Student findStudent(final Long studentId) {
    TypedQuery<Student> query = getEntityManager().createNamedQuery("from Student s where s.studentId =:studentId", Student.class);
    query.setParameter("studentId", studentId);
    query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
    query.setHint(JAVAX_PERSISTENCE_LOCK_TIMEOUT, ZERO_NUMBER);
    return query.getSingleResult();
}

@Override
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void updateStudent(Student student) {
    makePersistent(student);
    getEntityManager().flush();
}
...