Oznámení
Jakoby zanorene transakce
před 10 lety
- washo
- Generous Backer | 90
Napadla me takova vec:
class Faktura
{
private $polozky;
function delete()
{
dibi::beginSubTransaction();
foreach ($this->polozky as $polozka)
{
$polozka->delete();
}
dibi::query('DELETE FROM faktury ...');
// a dalsi veci
dibi::commitSubTransaction();
}
}
class Polozka
{
function delete()
{
dibi::beginSubTransaction();
dibi::query('DELETE FROM polozky ...');
//smaz jeste dalsi veci ktere nejsou treba v databazi
dibi::commitSubTransaction();
}
}
Slo by o to aby clovek nemusel psat:
$transaction = (! dibi::inTransaction());
if ($transaction) dibi::start();
neconeco
if ($transaction) dibi::commit();
Myslite ze je to blbos nebo dobry napad?
před 10 lety
- paranoiq
- Člen | 388
to už dibi umí – savepointy
viz: https://forum.dibiphp.com/…iewtopic.php?…
<?php
class Faktura
{
private $polozky;
function delete()
{
dibi::begin('faktura');
foreach ($this->polozky as $polozka)
{
$polozka->delete();
}
dibi::query('DELETE FROM faktury ...');
// a dalsi veci
dibi::commit('faktura');
}
}
class Polozka
{
function delete()
{
dibi::begin('polozka');
dibi::query('DELETE FROM polozky ...');
//smaz jeste dalsi veci ktere nejsou treba v databazi
dibi::commit('polozka');
}
}
?>
Editoval paranoiq (20. 3. 2009 14:29)
před 10 lety
- washo
- Generous Backer | 90
paranoiq napsal(a):
to už dibi umí – savepointy
viz: https://forum.dibiphp.com/…iewtopic.php?…
<?php class Faktura { private $polozky; function delete() { dibi::begin('faktura'); foreach ($this->polozky as $polozka) { $polozka->delete(); } dibi::query('DELETE FROM faktury ...'); // a dalsi veci dibi::commit('faktura'); } } class Polozka { function delete() { dibi::begin('polozka'); dibi::query('DELETE FROM polozky ...'); //smaz jeste dalsi veci ktere nejsou treba v databazi dibi::commit('polozka'); } } ?>
No to prave neni uplne ono. Save point chapu spis jako
dotaz
BEGIN
dotaz
dotaz
BEGIN jmeno
dotaz
dotaz
COMMIT jmeno
dotaz
dotaz
COMMIT
nevim jestli jde treba
BEGIN
dotaz
dotaz
BEGIN stejnejmeno
dotaz
BEGIN stejnejmeno
dotaz
dotaz
COMMIT stejnejmeno
dotaz
COMMIT stejnejmeno
dotaz
dotaz
COMMIT
a hlavne nechci vytvorit savepoint ale jenom „podtransakci“, ktera je soucasti nadrazene transakce pokud nejaka existuje. Pokud se ta zanorena transkace nezdari tak aby se nezdarila ani ta nadrazena. Co se stane kdyz transakce v ramci jednoho savepoiontu probehne v poradku ale nadrazeny savepoint (transakce) nekde selze? rollbackne se i ten spravne provedeny savepoint? Ja bych potreboval aby jo.
před 10 lety
- paranoiq
- Člen | 388
nevim jestli jde treba..
tak to samozřejmě nejde. pokud něco takového potřebujete, asi je něco špatně.
zřejmě jsem špatně pochopil o co vám jde. a možná i vy :]
když chcete ‚subtransakce‘, tak se napřed přesvědčete, zda to vaše databáze umí (mimochodem o jakou databázi vlastně jde?). co já vím, tak pg, mysql ani mssql nic takového jako ‚subtransakce‘ neumí a u jiných bych to také neočekával. chcete vědět proč?
není mi jasné, jak by jste chtěl implementovat subtransakce, aby bylo možné potvrdit subtransakci a zároveň nepotvrdit hlavní transakci (a tedy i příkazy provedené mezi začátkem hlavní transakce a začátkem subtransakce). je třeba také vzít v úvahu jak by paralelně běžící procesy přistupovaly k datům potvrzených subtransakcí v dosud nepotvrzené hlavní transakci
když se nad tím zamyslíte, možná vám z toho vyjde, že nic takového není možné. transakce je atomická operace, což samo o sobě naznačuje, že cokoliv jako 'sub'transakce je nesmyls
před 10 lety
- phx
- Člen | 652
Pokud to chapu dobra tak potrebujes jednu velkou transakci. Osobne jsem neco podobneho taky resil. (Napr kdyz komponenta vola komponentu a kazdy potrebuje delat neco v transakci a jednou kazda cast lze volat i samostatne)
Nakonec jsem to resil tak, ze vyvolam begin() a kdyz transakce bezi tak Dibi vyhodi vyjimku to zachytim a mam priznak zda jsem zacal/nezacal transakci. Pokud ano tak na konci comitnu a pokud ne tak se nestaram. Postara se ten kdo ji zacal. Problem je pouze s tim kdyz potrebuju udelat rollback a nezacal jsem transakci. V tu chvilu jsem pouze vyhozoval vyjimku a dle toho se nadrazeny kus kodu choval (rollbacknul).
před 10 lety
- washo
- Generous Backer | 90
Subtransakce je asi blbe slovo. To co chci neni vec databaze ale spis nejake podminene zehajeni transakce. Jde mi proste o to aby se vytvorila jedna velka transakce. Ale v kodu abych nemusel resit to jestli uz nejaka je a nebo ne.
phx napsal(a):
Pokud to chapu dobra tak potrebujes jednu velkou transakci. Osobne jsem neco podobneho taky resil. (Napr kdyz komponenta vola komponentu a kazdy potrebuje delat neco v transakci a jednou kazda cast lze volat i samostatne)
Nakonec jsem to resil tak, ze vyvolam begin() a kdyz transakce bezi tak Dibi vyhodi vyjimku to zachytim a mam priznak zda jsem zacal/nezacal transakci. Pokud ano tak na konci comitnu a pokud ne tak se nestaram. Postara se ten kdo ji zacal. Problem je pouze s tim kdyz potrebuju udelat rollback a nezacal jsem transakci. V tu chvilu jsem pouze vyhozoval vyjimku a dle toho se nadrazeny kus kodu choval (rollbacknul).
Jo to je presne to co potrebuju, akorat misto vyjimky to radsi testnu pomoci inTransaction(). Slo mi o to abych to prave nemusel furt testovat a potom zase commitovat pouze pokud jsem zahajil transakci.
Editoval washo (21. 3. 2009 12:39)
před 10 lety
- paranoiq
- Člen | 388
aha. tak už jsem se chyt. na slovech záleží :]
tohle by se dalo snadno vyřešit, kdyby si dibi pamatovalo jak byla transakce zahájena
v dibi je v begin() tento kód:
if ($savepoint && !$this->inTxn) {
$this->driver->begin();
}
$this->driver->begin($savepoint);
takže není nutné volat před savepointem založení transakce.
problém je, že pokud nevoláme begin() na začátku, zřejmě bude chybět i commit() na konci.. a to už dibi ošetřené nemá.
DibiConnection by si muselo zapamatovat jakým savepointem transakci zahájilo a při potvrzení tohoto savepointu celou transakci automaticky commitnout
výsledkem by bylo, že by se vůbec nemusel používat begin() a commit() bez parametru a tedy by odpadly všechny ty kontroly, zda jsme či nejsme v transakci
<?php
// nejsme v transakci a dibi automaticky zakládá transakci a savepoint 'aaa'. pamatuje si jeho jméno
dibi::begin('aaa');
...
// jsme v transakci a tak dibi pouze zakládá normální savepoint
dibi::begin('bbb');
...
// dibi zkontroluje zda je savepoint 'bbb' zahajovací a protože ne, tak pouze potvrdí savepoint
dibi::commit('bbb');
...
// dibi zkontroluje zda je savepoint 'aaa' zahajovací a protože ano, tak **automaticky commitne celou transakci**
dibi::commit('aaa');
?>
uvidíme co na to David.
Editoval paranoiq (21. 3. 2009 14:48)
před 10 lety
- phx
- Člen | 652
Stacilo by aby si begin() pamatoval kolikrat byl zavolat (prictal) a commit by odecital. Commitnul by pouze kdyz by byla 0.
Tedale na rychlo nejsme schopen vymyslet co by se delo pri rollback.
před 10 lety
- paranoiq
- Člen | 388
podle počtu zanoření to nejde, protože savepointy a jejich
potvrzení/zrušení nemusí být nutně v párech.
a dibi by asi neměla zavádět omezení nad rámec těch co jsou v databázi a
vynucovat párovost.
tohle je z pohledu db naprosto v pořádku:
BEGIN TRANSACTION; // buď voláním begin() nebo automaticky při AAA
SAVEPOINT AAA;
SAVEPOINT BBB;
SAVEPOINT CCC;
COMMIT; // buď voláním commit() nebo automaticky při AAA
na rollback() jsem nemyslel, ale pro ten by mělo platit asi to samé co pro commit().
Editoval paranoiq (21. 3. 2009 17:16)
před 10 lety
- phx
- Člen | 652
Asi si budu muset nastudovat SAVEPOINT.
Kapku tedy nechapu co potrebujes:(