Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да откриете, че транзакцията вече е започнала?

Рамката няма начин да разбере дали сте започнали транзакция. Можете дори да използвате $db->query('START TRANSACTION') за които рамката не би знаела, защото не анализира SQL изразите, които изпълнявате.

Въпросът е, че отговорността на приложението е да проследи дали сте започнали транзакция или не. Това не е нещо, което рамката може да направи.

Знам, че някои фреймворки се опитват да го направят и правят глупави неща като броене колко пъти сте започнали транзакция, като я разрешават само когато сте извършили ангажимент или връщане назад същия брой пъти. Но това е напълно фалшиво, защото никоя от функциите ви не може да знае дали commit или rollback наистина ще го направят, или дали са в друг слой на влагане.

(Можете ли да кажете, че съм водил тази дискусия няколко пъти? :-)

Актуализация 1: Propel е PHP библиотека за достъп до база данни, която поддържа концепцията за "вътрешната транзакция", която не се ангажира, когато й кажете. Започването на транзакция само увеличава брояча, а извършването/връщането намалява брояча. По-долу е даден откъс от нишка от пощенски списък, където описвам няколко сценария, при които не успява.

Актуализация 2: Doctrine DBAL също има тази функция. Наричат ​​го влагане на транзакции.

Харесвате или не, транзакциите са „глобални“ и не се подчиняват на обектно-ориентирано капсулиране.

Проблемен сценарий №1

Извиквам commit() , ангажименти ли са промените ми? Ако изпълнявам вътре във "вътрешна транзакция", те не са. Кодът, който управлява външната транзакция, може да избере да се върне назад и промените ми ще бъдат отхвърлени без мое знание или контрол.

Например:

  1. Модел А:започване на транзакция
  2. Модел A:изпълнете някои промени
  3. Модел Б:започване на транзакция (безшумно без операция)
  4. Модел Б:изпълнете някои промени
  5. Модел Б:извършване (безшумно без операция)
  6. Модел А:връщане назад (отхвърля както промените в модел А, така и промените в модел Б)
  7. Модел B:WTF!? Какво се случи с промените ми?

Проблемен сценарий №2

Вътрешна транзакция се връща назад, тя може да отхвърли законните промени, направени от външна транзакция. Когато контролът се върне към външния код, той вярва, че неговата транзакция все още е активна и е налична за ангажимент. С вашата корекция те биха могли да извикат commit() , и тъй като transDepth вече е 0, той ще зададе тихо $transDepth до -1 и върнете true, след като не сте извършили нищо.

Проблемен сценарий №3

Ако извикам commit() или rollback() когато няма активна транзакция, той задава $transDepth до -1. Следващият beginTransaction() увеличава нивото до 0, което означава, че транзакцията не може нито да бъде връщана назад, нито да бъде ангажирана. Последващи извиквания на commit() просто ще намали транзакцията до -1 или повече и никога няма да можете да извършите ангажимент, докато не направите още един излишен beginTransaction() за да увеличите нивото отново.

По принцип опитът да се управляват транзакции в логиката на приложението, без да се позволява на базата данни да води счетоводството, е обречена идея. Ако имате изискване за два модела да използват изричен контрол на транзакциите в една заявка за приложение, тогава трябва да отворите две DB връзки, по една за всеки модел. Тогава всеки модел може да има своя собствена активна транзакция, която може да бъде ангажирана или връщана назад независимо една от друга.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Group By с поръчка по

  2. Времето за изчакване на фиксиране на заключване е превишено; опитайте да рестартирате транзакцията за „заседнала Mysql таблица?

  3. MySQL избира бързо 10 произволни реда от 600K реда

  4. Синтаксис на SQL ALTER TABLE – Изброен от СУБД

  5. ПОРЪЧАЙТЕ ПО дата и час ПРЕДИ ГРУПА ПО име в mysql