tiny ‘n’ smart
database layer

Odkazy: dibi | API reference

Oznámení

Omlouváme se, provoz fóra byl ukončen

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:(