El marco no tiene forma de saber si inició una transacción. Incluso puede usar $db->query('START TRANSACTION')
que la infraestructura no conocería porque no analiza las sentencias SQL que ejecuta.
El punto es que es una aplicación la responsabilidad de rastrear si ha iniciado una transacción o no. No es algo que el marco pueda hacer.
Conozco algunos frameworks que tratan de hacerlo, y hago cosas divertidas como contar cuántas veces has comenzado una transacción, solo resolviéndola cuando has completado commit o rollback una cantidad de veces correspondiente. Pero esto es totalmente falso porque ninguna de sus funciones puede saber si el commit o el rollback realmente lo harán, o si están en otra capa de nesting.
(¿se puede decir que he tenido esta discusión un par de veces :-)
edición:?Propel es una biblioteca de acceso a la base de datos PHP que apoya el concepto de la "transacción interna" que no lo hace cometer cuando se lo digas. Comenzar una transacción solo incrementa un contador, y la confirmación/reposición disminuye el contador. A continuación se muestra un extracto de un hilo de la lista de correo donde describo algunos escenarios donde falla.
Nos guste o no, las transacciones son "globales" y no obedecen a la encapsulación orientada a objetos.
escenario Problema # 1
llamo commit()
, están comprometidos mis cambios? Si estoy ejecutando dentro de una "transacción interna", no lo están. El código que gestiona la transacción externa podría optar por retrotraerse y mis cambios se descartarían sin mi conocimiento o control.
Por ejemplo:
- Modelo A: iniciar la transacción
- Modelo A: ejecutar algunos cambios
- Modelo B: iniciar la transacción (silencio no-op)
- Modelo B: ejecutar algunos cambios
- Modelo B: confirmación (silenciosa no operativa)
- Modelo A: retrotracción (descarta los cambios del modelo A y los cambios del modelo B)
- Modelo B: ¿¡WTF !? ¿Qué pasó con mis cambios?
escenario Problema # 2
Una transacción interior deshace, se podría descartar los cambios legítimos hechas mediante una operación externa. Cuando se devuelve el control al código externo, cree que su transacción todavía está activa y disponible para comprometerse. Con su parche, podrían llamar al commit()
, y dado que transDepth ahora es 0, establecería silenciosamente $transDepth
en -1 y devolvería verdadero, después de no confirmar nada.
escenario Problema # 3
Si llamo commit()
o rollback()
cuando no hay transacción activa, se establece la $transDepth
a -1. El siguiente beginTransaction()
incrementa el nivel a 0, lo que significa que la transacción no se puede retrotraer ni comprometer. Las llamadas posteriores al commit()
simplemente disminuirán la transacción a -1 o más, y nunca podrá confirmar hasta que haga otro beginTransaction()
superfluo para incrementar el nivel nuevamente.
Básicamente, tratar de administrar las transacciones en la lógica de la aplicación sin permitir que la base de datos haga la contabilidad es una idea condenada. Si tiene un requisito para que dos modelos utilicen control de transacción explícito en una solicitud de aplicación, entonces debe abrir dos conexiones de base de datos, una para cada modelo. Luego, cada modelo puede tener su propia transacción activa, que puede comprometerse o retrotraerse de forma independiente entre sí.
(ver http://www.nabble.com/Zend-Framework-Db-Table-ORM-td19691776.html)
parece que esa cuestión se perdió en su programa de seguimiento ... :( – xelurg
Todos los temas ZF dicen "arreglar en la próxima versión menor" hasta que realmente fijos. Espero que tenían una buena razón para hacer eso, porque es bastante engañoso y causa confusión para mucha gente. –
En mi prueba a través del cliente mysql 'SELECT @@ autocommit;' todavía devuelve 1 durante una transacción. – ColinM