sql >> Base de Datos >  >> RDS >> Mysql

MySQL:transacciones vs tablas de bloqueo

El bloqueo de tablas evita que otros usuarios de la base de datos afecten las filas/tablas que ha bloqueado. Pero los bloqueos, por sí solos, 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 extrae el dinero. Y la cuenta del receptor, a la que se transfiere el dinero. Y la cuenta del banco, en la que felizmente depositarán todas las tarifas de servicio cobradas en la transacción. Dado (como todo el mundo sabe en 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 en la cuenta del receptor en paralelo. Si bien su código tiene su saldo recuperado y está haciendo enormes_overdraft_fees() y otras cosas, es muy posible que algún otro pago ejecute el mismo tipo de código en paralelo. Recuperarán su saldo (por ejemplo, $100), realizarán sus transacciones (sacarán los $20 que está pagando y los $30 con los que lo están fastidiando), y ahora ambas rutas de código tienen dos saldos diferentes:$80 y $70 Dependiendo de cuál termine en último lugar, terminará con cualquiera de esos dos saldos en su cuenta, en lugar de los $50 con los que debería haber terminado ($100 - $20 - $30). En este caso, "error bancario a su favor".

Ahora, digamos que usas 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... Intenta actualizar la cuenta del receptor, y está bloqueada, y bloqueada por más tiempo del que permite el código, agotando el tiempo de su transacción... Estamos tratando con bancos estúpidos, así que en lugar de tener el error correcto manejo, el código simplemente extrae un exit() , y tus $20 se desvanecen en una nube de electrones. Ahora te has quedado sin $20, y todavía le debes $20 al receptor, y tu teléfono es embargado.

Entonces... ingresa transacciones. Inicia una transacción, debita $20 de su cuenta, intenta acreditar $20 al receptor... y algo vuelve a explotar. Pero esta vez, en lugar de exit() , el código solo puede hacer rollback y puf, tus $20 se vuelven a agregar mágicamente a tu cuenta.

Al final, todo 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 haya hecho. 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.