Oznámení
PostgreSQL: Transakce a „current transaction is aborted…“
před 10 lety
- lucass
- Člen | 87
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)
před 10 lety
- Petr Motejlek
- Člen | 293
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)