Bloquear tablas evita que otros usuarios de la base de datos afecten las filas / tablas que ha bloqueado. Pero los bloqueos, por sí mismos, NO garantizarán que su lógica salga en un estado consistente.
Piense en un sistema bancario. Cuando paga una factura en línea, hay al menos dos cuentas afectadas por la transacción: Su cuenta, de la cual se toma el dinero. Y la cuenta del receptor, a la que se transfiere el dinero. Y la cuenta del banco, en la que depositarán felizmente todas las tarifas de servicio cobradas en la transacción. Dado (como todos saben estos días) que los bancos son extraordinariamente estúpidos, digamos que su sistema funciona así:
$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
Ahora, sin bloqueos ni transacciones, este sistema es vulnerable a varias condiciones de carrera, la mayor de las cuales son los pagos múltiples que se realizan en su cuenta o la cuenta del receptor en paralelo. Si bien su código tiene su saldo recuperado y está haciendo el enorme_sobredraft_fees () y todo eso, es muy posible que algún otro pago ejecute el mismo tipo de código en paralelo. Recuperarán su saldo (digamos, $ 100), harán sus transacciones (sacarán los $ 20 que está pagando y los $ 30 con los que lo están jodiendo), y ahora ambas rutas de código tienen dos saldos diferentes: $ 80 y $ 70. Dependiendo de cuáles terminen en último lugar, terminará con cualquiera de esos dos saldos en su cuenta, en lugar de los $ 50 que debería haber terminado ($ 100 - $ 20 - $ 30). En este caso, "error bancario a su favor"
Ahora, digamos que usa candados. El pago de su factura ($ 20) llega primero a la tubería, por lo que gana y bloquea el registro de su cuenta. Ahora tiene uso exclusivo y puede deducir los $ 20 del saldo y escribir el nuevo saldo en paz ... y su cuenta termina con $ 80 como se esperaba. Pero ... uhoh ... Intentas actualizar la cuenta del destinatario, y está bloqueada, y bloqueada más de lo que permite el código, agota el tiempo de tu transacción ... Estamos tratando con bancos estúpidos, así que en lugar de tener el error adecuado manejo, el código simplemente extrae unexit()
, y sus $ 20 se desvanecen en una nube de electrones. Ahora te quedaste con $ 20 y todavía le debes $ 20 al receptor, y tu teléfono es embargado.
Entonces ... ingrese transacciones. Comienzas una transacción, cargas en tu cuenta $ 20, intentas acreditar al receptor con $ 20 ... y algo vuelve a explotar. Pero esta vez, en lugar de exit()
, el código puede hacerrollback
, y puf, tus $ 20 se agregan mágicamente a tu cuenta.
Al final, se reduce a esto:
Los bloqueos evitan que nadie más interfiera con los registros de la base de datos con los que está tratando. Las transacciones evitan que los errores "posteriores" interfieran con las cosas "anteriores" que ha realizado. Ninguno de los dos por sí solo puede garantizar que las cosas salgan bien al final. Pero juntos lo hacen.
en la lección de mañana: The Joy of Deadlocks.