Simultaneidade quando usando GORM em Grails
-
03-07-2019 - |
Pergunta
Vamos dizer que tenho uma função de contador que atualiza um contador usando SQL puro:
public void updateCounter() {
executeSql("UPDATE counter SET count_value = count_value + 1 WHERE id = 1;");
}
O banco de dados seria certificar-se de que duas chamadas simultâneas para o contador são tratados como esperado -. Que todas as chamadas iria atualizar o contador com um incremento e nenhuma atualização iria se perder
Ao invés de executar isso emitindo um comando SQL cru que eu gostaria de usar GORM. A maneira ingênua de fazê-lo seria algo ao longo das linhas de:
public void updateCounter() {
Counter c = Counter.get(1)
c.countValue += 1
c.save()
}
Neste caso eu supor que uma atualização poderiam ser perdidos se dois threads chamar o método updateCounter () no mesmo momento. Qual é o "Grails / GORM-maneira" correta para lidar com este problema de concorrência?
Solução
Você pode usar tanto 'pessimistas' ou 'otimistas' bloqueio estratégias, que ambos suportados pelo Hibernate e, portanto, por GORM. A estratégia GORM padrão é 'otimista' (que utiliza a coluna de versão / propriedade da entidade de domínio persistente, criado por padrão). Pode ser usado como este:
...
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 você preferir a estratégia de bloqueio 'pessimista' em vez (que irá bloquear todos os outros concorrentes lê, btw), você poderia fazê-lo usando 'lock' explícita GORM meta-método, assim:
...
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
...
Espero que isso ajude.