php - numero - transacciones en mysql commit y rollback
Mysql transacciones dentro de las transacciones (7)
En un script PHP que trabaja con una base de datos mysql, recientemente tuve la necesidad de usar una transacción en un punto que sucedía dentro de otra transacción. Todas mis pruebas parecen indicar que esto está funcionando bien, pero no puedo encontrar ninguna documentación sobre este uso.
Quiero estar seguro: ¿las transacciones dentro de las transacciones son válidas en mysql? Si es así, ¿hay alguna forma de averiguar cuántos niveles profundos tiene en las transacciones anidadas? (es decir, cuántos retrocesos llevaría volver a la normalidad)
Gracias de antemano, Brian
Quiero estar seguro: ¿las transacciones dentro de las transacciones son válidas en mysql?
No.
Contrariamente a la respuesta de los demás, puede crear transacciones de manera efectiva dentro de las transacciones y es realmente fácil. Simplemente crea ubicaciones SAVEPOINT y usa ROLLBACK TO savepoint para deshacer parte de la transacción, donde savepoint es el nombre que le das al savepoint. Enlace a la documentación de MySQL: http://dev.mysql.com/doc/refman/5.0/en/savepoint.html Y, por supuesto, ninguna de las consultas en ninguna parte de la transacción debe ser del tipo que se confirma implícitamente, o la totalidad transacción será comprometida
Ejemplos:
START TRANSACTION;
# queries that don''t implicitly commit
SAVEPOINT savepoint1;
# queries that don''t implicitly commit
# now you can either ROLLBACK TO savepoint1, or just ROLLBACK to reverse the entire transaction.
SAVEPOINT savepoint2;
# queries that don''t implicitly commit
# now you can ROLLBACK TO savepoint1 OR savepoint2, or ROLLBACK all the way.
# e.g.
ROLLBACK TO savepoint1;
COMMIT; # results in committing only the part of the transaction up to savepoint1
En PHP, he escrito un código como este y funciona perfectamente:
foreach($some_data as $key => $sub_array) {
$result = mysql_query(''START TRANSACTION''); // note mysql_query is deprecated in favor of PDO
$rollback_all = false; // set to true to undo whole transaction
for($i=0;$i<sizeof($sub_array);$i++) {
if($sub_array[''set_save''] === true) {
$savepoint = ''savepoint'' . $i;
$result = mysql_query("SAVEPOINT $savepoint");
}
$sql = ''UPDATE `my_table` SET `x` = `y` WHERE `z` < `n`''; // some query/queries
$result = mysql_query($sql); // run the update query/queries
$more_sql = ''SELECT `x` FROM `my_table`''; // get data for checking
$result = mysql_query($more_sql);
$rollback_to_save = false; // set to true to undo to last savepoint
while($row = mysql_fetch_array($result)) {
// run some checks on the data
// if some check says to go back to savepoint:
$rollback_to_save = true; // or just do the rollback here.
// if some check says to rollback entire transaction:
$rollback_all = true;
}
if($rollback_all === true) {
mysql_query(''ROLLBACK''); // rollback entire transaction
break; // break out of for loop, into next foreach
}
if($rollback_to_save = true) {
mysql_query("ROLLBACK TO $savepoint"); // undo just this part of for loop
}
} // end of for loop
mysql_query(''COMMIT''); // if you don''t do this, the whole transaction will rollback
}
Es posible que desee verificar su metadología de prueba. Fuera de MaxDB , MySQL no admite nada de forma remota, como las transacciones anidadas.
Esta página del manual podría interesarle: 12.3.3. Declaraciones que causan un compromiso implícito ; citando unas pocas frases:
Las declaraciones enumeradas en esta sección (y cualquier sinónimos para ellas) terminan implícitamente una transacción, como si hubiera hecho un
COMMIT
antes de ejecutar la declaración.
Y, un poco más lejos en la página:
Declaraciones de control de transacciones y bloqueo.
BEGIN
,LOCK TABLES
,SET autocommit = 1
(si el valor aún no es 1),START TRANSACTION
,UNLOCK TABLES
.
Ver también este párrafo:
Las transacciones no se pueden anidar.
Esto es una consecuencia de lacommit
implícita realizada para cualquier transacción actual cuando se emite una declaraciónSTART TRANSACTION
o uno de sus sinónimos.
Hay algunas buenas respuestas en este hilo, sin embargo, si usa innoDB como su motor de almacenamiento MySQL y está utilizando MySQL 5.0.3 o superior, obtiene transacciones anidadas de manera inmediata sin la necesidad de ningún trabajo adicional de su parte o cualquiera de las técnicas de fantasía descritas por otros en este hilo.
Desde los documentos de MySQL en XA Transactions:
MySQL 5.0.3 y superiores proporcionan soporte en el lado del servidor para transacciones XA. Actualmente, este soporte está disponible para el motor de almacenamiento InnoDB. La implementación de MySQL XA se basa en el documento X / Open CAE Procesamiento distribuido de transacciones: la especificación XA. Este documento es publicado por The Open Group y está disponible en http://www.opengroup.org/public/pubs/catalog/c193.htm . Las limitaciones de la implementación XA actual se describen en la Sección E.5, "Restricciones en transacciones XA".
El ejemplo de transacción de mi XA solo para usted:
# Start a new XA transaction
XA START;
# update my bank account balance, they will never know!
UPDATE `bank_accounts` SET `balance` = 100000 WHERE `id` = ''mine'';
# $100,000.00 is a bit low, I''m going to consider adding more, but I''m not sure so
# I will start a NESTED transaction and debate it...
XA START;
# max int money! woo hoo!
UPDATE `bank_accounts` SET `balance` = 2147483647 WHERE `id` = ''mine'';
# maybe thats too conspicuous, better roll back
XA ROLLBACK;
# The $100,000 UPDATE still applies here, but the max int money does not, going for it!
XA COMMIT;
# Oh No! Sirens! It''s the popo''s!!! run!!
# What the hell are they using ints for money columns anyway! Ahhhh!
Documentación de MySQL para transacciones XA:
- 13.3.7. Transacciones XA
- 13.3.7.1. Sintaxis SQL de transacciones XA
- 13.3.7.2. XA Estados de transacción
- E.6. Restricciones en transacciones XA
I <3 XA Transacciones 4 Eva!
MySql no admite transacciones anidadas. Sin embargo, hay algunas formas en que puedes emularlo. En primer lugar, puede usar puntos de rescate como una forma de transacción, por lo que le da dos niveles de transacciones; Lo he usado para probar, pero no estoy seguro de las limitaciones, si lo usas en el código de producción. Una solución más simple es ignorar la segunda begin transaction
y en su lugar aumentar un contador. Para cada commit
, lo reduces. Una vez que llegue a cero, realiza una commit
real. Hay limitaciones obvias de esto; P.ej. una reversión retrotraerá todas las transacciones, pero para un caso en el que solo use transacciones para el manejo de errores, eso puede ser aceptable.