O bloqueio de tabelas evita que outros usuários do banco de dados afetem as linhas / tabelas que você bloqueou. Mas as travas, por si mesmas, NÃO garantirão que sua lógica saia em um estado consistente.
Pense em um sistema bancário. Quando você paga uma conta online, há pelo menos duas contas afetadas pela transação: Sua conta, da qual o dinheiro é retirado. E a conta do receptor, para a qual o dinheiro é transferido. E a conta do banco, na qual depositarão de bom grado todas as taxas de serviço cobradas na transação. Dado (como todos sabem atualmente) que os bancos são extraordinariamente estúpidos, digamos que seu sistema funcione assim:
$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;
$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance
Agora, sem bloqueios e sem transações, este sistema está vulnerável a várias condições de corrida, a maior das quais são vários pagamentos realizados em sua conta ou na conta do receptor em paralelo. Embora seu código tenha seu saldo recuperado e esteja executando o grande_overdraft_fees () e outros enfeites, é inteiramente possível que algum outro pagamento execute o mesmo tipo de código em paralelo. Eles recuperarão seu saldo (digamos, $ 100), farão suas transações (retire os $ 20 que você está pagando e os $ 30 com os quais estão enganando você) e agora os dois caminhos de código têm dois saldos diferentes: $ 80 e $ 70. Dependendo de qual terminar por último, você acabará com um desses dois saldos em sua conta, em vez dos $ 50 que deveria ter recebido ($ 100 - $ 20 - $ 30). Neste caso, "erro bancário a seu favor"
Agora, digamos que você use bloqueios. O pagamento da sua conta ($ 20) chega primeiro, então ganha e bloqueia o registro da sua conta. Agora você tem uso exclusivo, podendo deduzir os $ 20 do saldo, e reaver o novo saldo de volta em paz ... e sua conta fica com $ 80 como esperado. Mas ... uhoh ... Você tenta atualizar a conta do receptor, e ela está bloqueada, e bloqueada por mais tempo do que o código permite, expirando sua transação ... Estamos lidando com bancos estúpidos, então, em vez de ter o erro adequado manipulando, o código apenas puxa um exit()
, e seus $ 20 desaparecem em uma nuvem de elétrons. Agora você está sem $ 20 e ainda deve $ 20 ao receptor, e seu telefone é retomado.
Então ... insira as transações. Você inicia uma transação, debita $ 20 de sua conta, tenta creditar o receptor com $ 20 ... e algo explode novamente. Mas desta vez, em vez de exit()
, o código pode apenas fazer rollback
, e puf, seus $ 20 são magicamente adicionados de volta à sua conta.
No final, tudo se resume a isso:
Os bloqueios impedem que qualquer outra pessoa interfira nos registros do banco de dados com os quais você está lidando. As transações evitam que quaisquer erros "posteriores" interfiram nas coisas "anteriores" que você fez. Nenhum dos dois pode garantir que tudo dê certo no final. Mas juntos, eles fazem.
na lição de amanhã: The Joy of Deadlocks.