Em uma tabela em que cada linha tem um contador (apenas um valor inteiro), preciso obter o valor atual e aumentá-lo ao mesmo tempo .
Efetivamente, eu quero fazer isso:
SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123
Mas fazer isso como duas consultas obviamente não é seguro para threads: vários processos que fazem a mesma coisa (na mesma linha) podem obter o mesmo valor de contador. Eu preciso que todos sejam únicos, para que cada processo obtenha o valor atual real e o aumente em um.
Posso pensar em uma construção em que implemento um bloqueio manual por linha, mas me pergunto se existe uma maneira mais fácil de fazer isso.
Respostas:
As instruções de atualização funcionam perfeitamente sem a seleção anterior! Como instruções únicas são seguras por definição, mesmo duas consultas UPDATE executadas ao mesmo tempo resultarão na linha incrementada duas vezes.
Se você realmente deseja selecionar o valor para o seu script PHP, faça algo com ele e depois deseje atualizar esse valor exato do contador, faça o seguinte:
Isso inicia uma nova transação, seleciona as linhas que você deseja atualizar e as bloqueia exclusivamente. Você pode atualizar com segurança aqueles sem se preocupar com outros clientes alterando seu conteúdo ou mesmo acessando as linhas bloqueadas. Finalmente, você precisa confirmar suas alterações.
Você também deve ler algo sobre os níveis de isolamento . Você provavelmente não deseja um valor como
READ UNCOMMITTED
nível de isolamento. Tudo o resto deve ficar bem para este caso de uso.fonte
UPDATE table SET counter = counter + 1
é suficientemente atômico? Você ainda precisa das instruções de transação que o cercam?FOR UPDATE
transações, o valor selecionado poderá ser diferente daquele usado na consulta de atualização. Minha combinação de consultas bloqueia a linha assim que o valor é selecionado e, portanto, garante que esse valor exato do contador seja usado na consulta de atualização.