transacciones ejemplos ejemplo clase php mysql pdo transactions

php - clase - transacciones en mysql ejemplos



Comprender las transacciones pdo mysql (3)

La documentación de PHP dice:

Si nunca antes ha encontrado transacciones, ofrecen 4 características principales: Atomicidad, Consistencia, Aislamiento y Durabilidad (ACID). En términos simples, cualquier trabajo realizado en una transacción, incluso si se realiza por etapas, se garantiza que se aplicará a la base de datos de forma segura y sin interferencia de otras conexiones, cuando se comete.

PREGUNTA:

¿Significa esto que puedo tener dos scripts php separados que ejecutan transacciones simultáneamente sin que interfieran entre sí?

ELABORANDO SOBRE LO QUE QUIERO DECIR " INTERFERIR " :

Imagine que tenemos la siguiente tabla de employees :

__________________________ | id | name | salary | |------+--------+----------| | 1 | ana | 10000 | |------+--------+----------|

Si tengo dos scripts con código similar / mismo y se ejecutan exactamente al mismo tiempo:

script1.php y script2.php (ambos tienen el mismo código):

$conn->beginTransaction(); $stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?"); $stmt->execute([''ana'']); $row = $stmt->fetch(PDO::FETCH_ASSOC); $salary = $row[''salary'']; $salary = $salary + 1000;//increasing salary $stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?"); $stmt->execute([''ana'']); $conn->commit();

y suponiendo que la secuencia de eventos es la siguiente:

  • script1.php selecciona datos

  • script2.php selecciona datos

  • script1.php actualiza datos

  • script2.php actualiza datos

  • script1.php commit () sucede

  • script2.php commit () sucede

¿Cuál sería el salario resultante de ana en este caso?

  • ¿Sería 11000? ¿Y esto significaría que 1 transacción se superpondrá con la otra porque la información se obtuvo antes de que ocurriera cualquiera de las confirmaciones?

  • ¿Sería 12000? ¿Y esto significaría que, independientemente del orden en que se actualizaron y seleccionaron los datos, la función commit() obligó a suceder individualmente?

No dude en elaborar todo lo que quiera sobre cómo las transacciones y los scripts separados pueden interferir (o no interferir) entre sí.


A juzgar por las condiciones dadas (una declaración DML solitaria), no necesita una transacción aquí, sino un bloqueo de tabla. Es una confusión muy común.

Necesita una transacción si necesita asegurarse de que TODAS sus declaraciones DML se realizaron correctamente o no se realizaron en absoluto.

Medio

  • no necesita una transacción para ninguna cantidad de consultas SELECT
  • no necesita una transacción si solo se realiza una declaración DML

Aunque, como se señaló en la excelente respuesta de Shadow, puede usar una transacción aquí con el nivel de aislamiento adecuado, sería bastante confuso. Lo que necesita aquí es el bloqueo de la mesa . El motor InnoDB le permite bloquear filas particulares en lugar de bloquear toda la tabla y, por lo tanto, debería preferirse.

En caso de que desee que el salario sea de 1200, use cerraduras de mesa.

O, de una manera más simple, simplemente ejecute una consulta de actualización atómica :

UPDATE employees SET salary = salary + 1000 WHERE name = ?

En este caso se registrarán todos los salarios.

Si su objetivo es diferente, mejor expresarlo explícitamente.

Pero de nuevo: debe comprender que las transacciones en general no tienen nada que ver con la ejecución de scripts separados. Con respecto a su tema de condición de carrera, no le interesan las transacciones, sino el bloqueo de tablas / filas. Esta es una confusión muy común, y es mejor que la aprenda directamente:

  • una transacción es para garantizar que un conjunto de consultas DML dentro de un script se ejecutaron con éxito.
  • el bloqueo de tabla / fila es para garantizar que otras ejecuciones de script no interfieran.

El único tema en el que interfieren las transacciones y el bloqueo es un deadlock , pero nuevamente, es solo en el caso de que una transacción esté usando el bloqueo.


No encontrará la respuesta en la documentación de php porque esto no tiene nada que ver con php o pdo.

El motor de tabla Innodb en mysql ofrece 4 niveles de aislamiento llamados en línea con el estándar sql. Los niveles de aislamiento junto con las lecturas de bloqueo / no bloqueo determinarán el resultado del ejemplo anterior. Debe comprender las implicaciones de los distintos niveles de aislamiento y elegir el apropiado para sus necesidades.

En resumen: si usa un nivel de aislamiento serializable con el autocompromiso desactivado, el resultado será 12000. En todos los demás niveles de aislamiento y serializable con el autocompromiso habilitado, el resultado será 11000. Si comienza a usar lecturas de bloqueo, entonces el resultado podría ser 12000 bajo todos los niveles de aislamiento.


Por desgracia, el "sin interferencia" necesita ayuda del programador. Necesita BEGIN y COMMIT para definir el alcance de la ''transacción''. Y...

Tu ejemplo es inadecuado. La primera declaración necesita SELECT ... FOR UPDATE . Esto le dice al procesamiento de la transacción que es probable que haya una UPDATE para las filas que SELECT obtiene. Esa advertencia es crítica para "evitar interferencias". Ahora la línea de tiempo dice:

  • script1.php COMIENZA
  • script2.php COMIENZA
  • script1.php selecciona datos ( FOR UPDATE )
  • script2.php selecciona datos que están bloqueados, por lo que espera
  • script1.php actualiza datos
  • script1.php commit () sucede
  • script2.php selecciona datos (y obtendrá el valor recién confirmado)
  • script2.php actualiza datos
  • script2.php commit () sucede

(Nota: Esto no es un ''punto muerto'', solo una ''espera'').