Framework nie ma możliwości sprawdzenia, czy rozpocząłeś transakcję. Możesz nawet użyć $db->query('START TRANSACTION')
o których framework nie wiedziałby, ponieważ nie analizuje wykonywanych instrukcji SQL.
Chodzi o to, że obowiązkiem aplikacji jest śledzenie, czy rozpocząłeś transakcję, czy nie. To nie jest coś, co może zrobić framework.
Wiem, że niektóre frameworki próbują to zrobić i robią takie rzeczy, jak liczenie, ile razy rozpocząłeś transakcję, rozwiązując ją tylko wtedy, gdy wykonałeś zatwierdzenie lub wycofałeś pasującą liczbę razy. Ale jest to całkowicie fałszywe, ponieważ żadna z twoich funkcji nie może wiedzieć, czy zatwierdzenie lub wycofanie faktycznie to zrobi, czy też znajdują się w innej warstwie zagnieżdżenia.
(Czy możesz powiedzieć, że miałem taką dyskusję kilka razy? :-)
Aktualizacja 1: Śmigło jest biblioteką dostępu do bazy danych PHP, która obsługuje koncepcję „transakcji wewnętrznej”, która nie zostaje zatwierdzona, gdy jej polecisz. Rozpoczęcie transakcji tylko zwiększa licznik, a zatwierdzenie/wycofanie zmniejsza licznik. Poniżej znajduje się fragment wątku listy dyskusyjnej, w którym opisuję kilka scenariuszy, w których się nie udaje.
Aktualizacja 2: Doktryna DBAL ma również tę funkcję. Nazywają to zagnieżdżaniem transakcji.
Czy ci się to podoba, czy nie, transakcje są „globalne” i nie podlegają enkapsulacji obiektowej.
Scenariusz problemu nr 1
Dzwonię do commit()
, czy moje zmiany są zatwierdzone? Jeśli działam wewnątrz „transakcji wewnętrznej”, nie są. Kod zarządzający transakcją zewnętrzną może wycofać się, a moje zmiany zostaną odrzucone bez mojej wiedzy i kontroli.
Na przykład:
- Model A:rozpocznij transakcję
- Model A:wykonaj pewne zmiany
- Model B:rozpocznij transakcję (cichy brak operacji)
- Model B:wykonaj pewne zmiany
- Model B:zatwierdzenie (cichy brak operacji)
- Model A:wycofanie (odrzuca zarówno zmiany modelu A, jak i zmiany modelu B)
- Model B:WTF!? Co się stało z moimi zmianami?
Scenariusz problemu nr 2
Wewnętrzna transakcja wycofuje się, może odrzucić uzasadnione zmiany wprowadzone przez transakcję zewnętrzną. Gdy kontrola jest zwracana do kodu zewnętrznego, uważa, że jego transakcja jest nadal aktywna i dostępna do zatwierdzenia. Z twoją łatką mogą wywołać commit()
, a ponieważ transDepth wynosi teraz 0, po cichu ustawi $transDepth
do -1 i zwróć prawdę, jeśli nic nie zrobisz.
Scenariusz problemu nr 3
Jeśli wywołam commit()
lub rollback()
gdy nie ma aktywnej transakcji, ustawia $transDepth
do -1. Następna beginTransaction()
zwiększa poziom do 0, co oznacza, że transakcja nie może zostać wycofana ani zatwierdzona. Kolejne wywołania commit()
po prostu zmniejszy transakcję do -1 lub więcej i nigdy nie będziesz w stanie zatwierdzić, dopóki nie zrobisz kolejnego zbędnego beginTransaction()
aby ponownie zwiększyć poziom.
Zasadniczo próba zarządzania transakcjami w logice aplikacji bez pozwalania na prowadzenie księgowości przez bazę danych jest straconym pomysłem. Jeśli istnieje wymaganie, aby dwa modele używały jawnej kontroli transakcji w jednym żądaniu aplikacji, należy otworzyć dwa połączenia bazy danych, po jednym dla każdego modelu. Następnie każdy model może mieć własną aktywną transakcję, która może zostać zatwierdzona lub wycofana niezależnie od siebie.