dôvod prečo sa pýtam:
V php mam objekt nad ktorým keď zavolám metódu, vykoná sa transakcia operácií. V prípade prolému sa to celé vrati (rollback) a metóda vyhodí výnimku. Teraz ale potrebujem nad množstvom objektov tejto triedy vyvolať túto metódu, a potrebujem zaručiť, že sa vykonajú všetky, ak nie, chcem všetko vrátiť.
zjednodušený príklad kódu:
class simpleObject
{
public function doSomethingCool()
{
begin
try
{
query
query
query
}
catch()
{
rollback
throw
}
commit
}
}
class listOfSimpleObjects
{
/** @var array An array of {@link simpleObject} objects.
private $list;
public function doSomethingCoolWithAllObjects()
{
begin
try
{
foreach($this->list as $obj) $obj->doSomethingCool();
}
catch ()
{
rollback
throw;
}
commit
}
Nikde na mysql som sa nedočítal o volaní begin za beginom - vnorených transakciách, a asi to ani nepôjde.
Napadlo ma preto riešenie, a chcel by som vedieť vaše názory, prípadne mi prosím navrhnite iné riešenie.
Riešenie spočíva v použití savepointov a "bufferovaní" beginov. Odskúšať už nestíham, no ak s tým má niekto skúsenosti, prípadne to niekoho zaujalo, prosím o názor / skúsenosti.
// počítadlo hĺbky transakcie:
$t_depth = 0;
/**
* Pre zacatie transakcie sa pouzije tato metoda,
* v pripade, ze este nebola zacata transakcia, zabola sa BEGIN
* inak sa zavola savepoint a nazov savepointu bude aktualna hlbka.
*/
function t_begin()
{
if ($t_depth === 0)
{
BEGIN
}
else
SAVEPOINT (++$t_depth);
}
/**
* funkcia pre commit. V pripade ze hlbka transakcii je 1, zavola sa commit, v pripade, ze hlbka je vacsia,
* cislo hlbky sa iba znizi
*/
function t_commit()
{
if ($t_depth === 1)
{
COMMIT
}
$t_depth--;
}
/**
* funkcia pre rollback. V pripade ze hlbka transakcie je 1 zavola sa rollback, v pripade ze hlbka je vacsia
* zavola sa rollback to savepoint kde nazov savepointu na ktory sa vracam je aktualna hlbka
* nakoniec sa hlbka dektrementuje
*/
function t_rollback()
{
if ($t_depth === 1)
{
ROLLBACK
}
else
{
ROLLBACK TO SAVEPOINT $t_depth
}
$t_depth--;
}