Вопрос

Допустим, у меня есть функция счетчика, которая обновляет счетчик с помощью необработанного SQL:

 public void updateCounter() {
   executeSql("UPDATE counter SET count_value = count_value + 1 WHERE id = 1;");
 }

База данных будет гарантировать, что два одновременных вызова счетчика будут обрабатываться, как и ожидалось, - что все вызовы будут обновлять счетчик с одним шагом, и обновления не будут потеряны.

Вместо того, чтобы выполнять это, выполнив необработанную команду SQL, я бы хотел использовать GORM. Нашим способом сделать это было бы что-то вроде:

 public void updateCounter() {
   Counter c = Counter.get(1)
   c.countValue += 1
   c.save()
 }

В этом случае я бы предположил, что обновление может быть потеряно, если два потока вызовут метод updateCounter () одновременно. Что такое правильный "Grails / GORM-way"? справиться с этой проблемой параллелизма?

Это было полезно?

Решение

Вы можете использовать «пессимистическую» или «оптимистическую» стратегию блокировки, которая поддерживается Hibernate и, следовательно, GORM. Стратегия GORM по умолчанию - «оптимистическая» (которая использует столбец версии / свойство персистентной сущности домена, созданной по умолчанию). Это можно использовать так:

...
try {
 Counter c = Counter.get(1)
 c.countValue += 1
 c.save(flush:true)
}
catch(org.springframework.dao.OptimisticLockingFailureException e) {
// deal with concurrent modification here
}
...

Если вы предпочитаете стратегию «пессимистической» блокировки (которая блокирует все другие параллельные чтения, кстати), вы можете сделать это, используя явный мета-метод GORM «блокировка», например, так:

...
Counter c = Counter.lock(1) //lock the entire row for update
c.countValue += 1
c.save(flush:true) //GORM will autorelease the lock once the TX is committed
...

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top