Odkazy: dibi | API reference

Forum: [česky] [english]

dibi fórum

tiny ‘n’ smart
database layer

Nejste přihlášen(a)

#1 před 2 lety

lucass
Člen
Registrovaný: 4. 12. 2008
Příspěvky: 80

PostgreSQL: Transakce a „current transaction is aborted…“

Zdravím,

asi jsem objevil Ameriku, ale pro jistotu to sem píšu jako obecnou zkušenost s transakcemi v PostgreSQL, kdyby někdo řešil podobnou věc.

Nějaký čas jsem strávil nad hledáním této chyby:

current transaction is aborted, commands ignored until end of transaction block unique

Ve své metodě save() mám následující blok:

<?php

public function save($data, $id = false) {
        ...
        try {

                dibi::begin(get_class($this));

                // vlastni ulozeni pole $data

                dibi::commit(get_class($this));
        } catch (DibiException $e) {
                $this->result->error = $e->getMessage();
        }
        ...
}

?>

Přestože DibiException byla odchycena, tj. ocitl jsem se v catch bloku, aplikace celkově stejně padla na pozdějším DibiDriverException + výše zmíněná hláška. Chyba se stávala jen v případě, kdy jsem nad tabulkou, do níž ukládám, vytvořil UNIQUE CONSTRAINT či UNIQUE INDEX.

Po debugu a hledání po netu jsem nakonec zjistil, že chyba, protože je nalezena asi v hlubší vrstvě (kdyby to někdo dokázal vysvětlit přesněji, budu rád), je v rollbacku. V catch bloku, kdy je odchycena DibiException, je nutné doplnit následující:

<?php
        ...
        } catch (DibiException $e) {
                dibi::rollback(get_class($this)); // nutne

                $this->result->error = $e->getMessage();
        }
        ...
?>

Jak říkám, asi je to přístup samozřejmý, ale doposud mi dostačovalo jen odchytávat výjimky bez rollbacků a nikdy jsem se s tím nesetkal.

Editoval lucass (17. 11. 2009 22:15)

 

#2 před 2 lety

Petr Motejlek
dibi guru
Registrovaný: 9. 1. 2009
Příspěvky: 325

Re: PostgreSQL: Transakce a „current transaction is aborted…“

Tohle téma už je trošku starší, ale když tak koukám na ten zápis, tak mi to nedá, a musím se zeptat ;). Co se bude dít, když ten dibi::rollback(…) vyhodí výjimku? Např. že hapala databáze?

Vím, že to je trošku podivný scénář, ale co kdyby dotaz v dibi::query(…) byl například syntakticky špatně (klidně to ale může být chyba vstupních dat) a dibi by vyhodila výjimku (databáze v klidu běží, otestovala dotaz a zjistila chybu, tak posílá do vyšší úrovně hlášku, že je něco špatně), já bych tu výjimku chytil, ale první, co bych dělal by byl dibi::rollback(…), v tu chvíli by ale databáze náhle spadla (takovej deus ex efekt, nebo tak něco ;)), nebo by někdo přerušil spojení mezi strojem, kde běží PHP a strojem, kde běží databáze. Teď by mi aplikace umřela s hláškou, že spadla databáze, což sice není špatně, ale to, že mám v aplikaci špatně dotaz, se dozvím možná až když za nějakou dobu někdo znovu použije můj kód… Nebylo by lepší to koncipovat spíš jako

<?php
$query = 'SELECT * FROM [myTable]';

try {
  dibi::begin();
} catch (Exception $e) {
  Debug::processException($e);
  throw $e;
};

try {
  dibi::query($query);
  dibi::commit();
} catch (Exception $e) {
  Debug::processException($e);

  try {
    dibi::rollback();
  } catch (Exception $f) {
    Debug::processException($f);
    throw $f;
  };

  throw $e;
};
?>

Možná to je trochu overkill, ale zase tomu už nic neuteče ;). Budu rád, když se tady ostatní vyjádří, jak je to podle nich nejlepší dělat. Díky ;)

Editoval Petr Motejlek (10. 12. 2009 15:39)

 

Zápatí