Domanda

Diciamo che ho una funzione contatore che aggiorna un contatore usando SQL grezzo:

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

Il database si assicurerebbe che due chiamate simultanee al contatore vengano gestite come previsto - che tutte le chiamate aggiornerebbero il contatore con un incremento e nessun aggiornamento andrebbe perso.

Piuttosto che eseguirlo eseguendo un comando SQL non elaborato, mi piacerebbe utilizzare GORM. Il modo ingenuo di farlo sarebbe qualcosa sulla falsariga di:

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

In questo caso suppongo che un aggiornamento potrebbe andare perso se due thread chiamano il metodo updateCounter () nello stesso momento. Qual è la corretta "quotazione Grails / GORM" gestire questo problema di concorrenza?

È stato utile?

Soluzione

È possibile utilizzare strategie di blocco "pessimistiche" o "ottimistiche", entrambe supportate da Hibernate e quindi da GORM. La strategia GORM predefinita è "ottimista" (che utilizza la colonna / proprietà della versione dell'entità di dominio persistente, creata per impostazione predefinita). Potrebbe essere usato in questo modo:

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

Se invece preferisci la strategia di blocco 'pessimista' (che bloccherà tutte le altre letture simultanee, tra l'altro), potresti farlo usando il meta-metodo GORM esplicito 'lock', in questo modo:

...
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
...

Spero che questo aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top