Transacciones
Drupal también soporta transacciones, incluyendo una alternativa transparente para bases de datos que no soportan transacciones. Sin embargo, las transacciones pueden ser bastante complejas si intentas ejecutar dos transacciones simultáneamente. El comportamiento en este caso también depende de la base de datos.
Un problema similar existe con los bloqueos anidados en C / C++. Si el código ya ha adquirido el bloqueo A y trata de adquirir el bloqueo A nuevamente, el código quedará bloqueado. Si escribes código que verifica si ya posee un bloqueo y evita adquirirlo de nuevo, evitas un interbloqueo pero podrías liberar el bloqueo prematuramente.
En SQL tenemos el mismo problema. Si tu código ya está en una transacción, iniciar una nueva transacción tiene la consecuencia inesperada y no deseada de confirmar la transacción actual y comenzar una nueva.
Java resuelve el problema de la anidación en sus bloqueos implementando soporte para estructuras anidadas, similar a la que probamos abajo. Java permite marcar funciones como “síncronas”, lo que hace que la función espere a adquirir el bloqueo antes de ejecutarse y libere el bloqueo cuando ya no se necesita. Si una función sincronizada llama a otra dentro de la misma clase, Java controla la anidación del bloqueo. La función externa adquiere el bloqueo, la función interna no realiza operaciones de bloqueo y la función externa libera el bloqueo al regresar.
Aunque no podemos declarar funciones como “transactional” en PHP, podemos emular la lógica anidada de Java usando objetos con constructores y destructores. La función simplemente llama a “$transaction = $connection->startTransaction()” como primera (o casi primera) operación para hacerse transactional. Si una función transactional llama a otra, nuestro nivel de abstracción de transacciones las anida sin ejecutar operaciones transactionales (desde la perspectiva de la base de datos) dentro de los niveles internos anidados.
Para iniciar una nueva transacción, simplemente llama a $transaction = $connection->startTransaction(); en tu propio código. La transacción permanecerá abierta mientras la variable $transaction esté en el ámbito. Cuando $transaction es destruida, la transacción se confirma. Si tu transacción está anidada dentro de otra, Drupal rastreará cada transacción y solo confirmará la transacción externa cuando el último objeto transacción salga del ámbito, es decir, cuando todas las consultas relacionadas hayan sido exitosamente completadas.
Debes asignar el valor retornado de $connection->startTransaction(); a una variable, como en el ejemplo. Si llamas al método sin asignar el valor retornado a una variable, tu transacción se confirmará instantáneamente, lo que la hará inútil.
El rollback de la transacción es manejado por el objeto conexión ($connection->rollBack()) en Drupal 8, pero generalmente debería ejecutarse a través del método envolvente de la transacción ($transaction->rollBack()). La razón por la cual debería hacerse con el método rollBack() de la transacción es que revierte esa transacción basada en su nombre, mientras que $connection->rollBack() usa por defecto el nombre drupal_transaction y puede producir resultados indeseados cuando se usa con transacciones anidadas.
Ejemplo:
function my_transaction_function() { // Aquí se abre la transacción. $transaction = $connection->startTransaction(); try { $id = $connection->insert('example') ->fields([ 'field1' => 'mystring', 'field2' => 5, ]) ->execute(); my_other_function($id); return $id; } catch (Exception $e) { $transaction->rollBack(); watchdog_exception('my_type', $e); } // Puedes dejar que $transaction salga del ámbito aquí y la transacción // se confirmará automáticamente si no fue revertida. // Sin embargo, si tienes más trabajo por hacer, querrás confirmar la transacción // tú mismo, así: $transaction->commit(); // Más código aquí fuera de la transacción. } function my_other_function($id) { // La transacción aún está abierta aquí. if ($id % 2 == 0) { $connection->update('example') ->condition('id', $id) ->fields(['field2' => 10]) ->execute(); } }
Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.