PHP und Sqlite Transaktionen

Ich bin ja Fan von sqlite, besonders für kleinere Projekte, wo kein hohes paralelles Schreiben zu erwarten ist, also für fast alle kleineren Seiten.
Keine Datenbank Administration, einfach loslegen und schnell ist es auch noch.

Ein paar Krücken gibts aber schon, zB bei Transaktionen (die MySql im Regelfall gar nicht kann ;)).
Ich benutze die in diesem Fall für multiple Inserts, um da Performance rauszuschlagen.

Über diese bin ich letztens noch gestolpert:

1. Es ist keine gute Idee Transaktionen zu stückeln und sequentiell abzuarbeiten.(warum auch immer man auf diese Idee kommt ;))
besser ist: alle Queries zu buffern und dann in einer Transaktion auszuführen.
Denn Transaktionen locken die DB und nach meiner Erfahrung kann das PHP SQLiteDatabase Object den Datenbank Cursor nicht richtig schließen.
Das führt dann zu sowas: “cannot start a transaction within a transaction”

Folgender Code:

for ($i = 0 ; $i < count($data) ; $i++) {
	$q='BEGIN;';
	$q.="INSERT INTO ".$this->table." (bla) VALUES ('blub');";
	$q.='COMMIT;';	
	$this->_db->query($q);
}

wird also nicht klappen.

Bei PDO gibt es da wohl bessere Unterstützung für Transaktionen.
Das PHP SQLiteDatabase Object ist da etwas kryptisch.

2. ->query() mag keine Transaktionen, ->queryExec() jedoch schon.
Wahrscheinlich deswegen :

SQLite führt Mehrfach-Anfragen, die durch Semikolon getrennt wurden, aus, so dass Sie Anfragen ausführen können, die aus einer Datei oder über ein Skript geladen wurden. Wie auch immer, das funktioniert nur, wenn das Ergebins der Anfrage nicht benutzt wird. Sollte es doch genutzt werden, wird nur die erste SQL-Anfrage der Liste ausgeführt. Die Funktion sqlite_exec() wird immer Mehrfach-Anfragen ausführen.

Wenn Mehrfach-Anfrage ausgeführt werden, wird die Funktion im Fehlerfall FALSE zurückgeben, anderenfalls jedoch ein undefiniertes Ergebnis (das kann, sollte die Anfrage gelingen, TRUE oder ein Ergebnis-Handle sein).

Also ->queryExec() kanns und ->query kanns irgendwie nicht.
Dort würde nur der erste query ausgeführt und der Rest stillschweigend ignoriert, d.h. die Anweisung gibt true zurück.
Es würde also viele Tupel -unbemerkt- verlorengehen.

Folgender Code hingegen klappt dann:

$q='';
$this->_db->queryExec('BEGIN;');
for ($i = 0 ; $i < count($data) ; $i++) {
	$q.="INSERT INTO ".$this->table." (bla) VALUES ('blub');";
}
$this->_db->queryExec($q);
$this->_db->queryExec('COMMIT;');

Diese Seite war dabei übrigens recht hilfreich:
http://www.ordix.de/ORDIXNews/1_2004/unix_linux_2.html

Ja krass, gar kein Framework benutzt hier! ;)