Transaction - aber wie?

Transaction - aber wie?

am 15.05.2007 22:19:19 von Andreas Horn

Hallo ng,

ich habe folgende Konstruktion:
Client mit Webzugriff -> Apache/PHP -> MySQL/InnoDB.
Generator ist CodeChargeStudio (http/mysql).
Ich möchte gerne Transaktionen verwenden. Dazu starte ich eine
Verbindung (connect), kann aber mit immer nur 1 SQL-Befehl absetzen.
Danach wird (bei nicht-permanenter Verbindung) die Verbindung beendet
und zum Absetzen eines neuen SQL-Befehls eine neue Verbindung aufgebaut.
Jetzt bin ich unsicher, ob eine Transaktion nur innerhalb einer
Verbindung ablaufen kann, wie sollte sonst das DBMS wissen, ob von
diesem Client ein weiterer zu dieser Transaktion gehörender SQL-Befehl
kommt? Wegen der programmgesteuerten Auswertung (und auch wegen noch
fehlender Ahnung) fällt es mir auch schwer, alles in eine Stored
Procedure oder in Trigger auszulagern.

Meine Frage ist eigentlich:
Wie stelle ich es an, eine Transaktion mit mehreren SQL-Befehlen
abzusenden, wenn jeder SQL-Befehl eine eigene Verbindung hat? Oder habe
ich hier nur noch einen RTFM-Fehler und es geht doch?

Danke schon mal
Andreas

Re: Transaction - aber wie?

am 15.05.2007 23:28:43 von Dominik Echterbruch

Andreas Horn schrieb:
>
> Ich möchte gerne Transaktionen verwenden. Dazu starte ich eine
> Verbindung (connect), kann aber mit immer nur 1 SQL-Befehl absetzen.
> Danach wird (bei nicht-permanenter Verbindung) die Verbindung beendet
> und zum Absetzen eines neuen SQL-Befehls eine neue Verbindung aufgebaut.

Stellt sich mir die Frage nach dem Sinn. Lass doch die Verbindung offen,
wenn du weißt, daß noch weitere Abfragen folgen werden (und wenn es nur
das COMMIT oder ROLLBACK ist).

Oder meinst du vielleicht, daß die Transaktion immer sofort wieder
beendet wird? Das wäre dann ein Fall von auto_commit = On (oder so
ähnlich bin grad zu faul zum nachschauen) in der MySQL Konfiguration.

Vielleicht hast du aber auch das BEGIN vergessen, das die Transaktion
einleitet?

> Jetzt bin ich unsicher, ob eine Transaktion nur innerhalb einer
> Verbindung ablaufen kann, wie sollte sonst das DBMS wissen, ob von
> diesem Client ein weiterer zu dieser Transaktion gehörender SQL-Befehl

Damit hast du dir die Frage selber beantwortet :) AFAIK ist eine
Transaktion immer an eine Verbindung gebunden (lustiger Satz) und wird
automatisch mit einem ROLLBACK beendet, wenn die Verbindung ohne
explizites COMMIT abbricht.

> kommt? Wegen der programmgesteuerten Auswertung (und auch wegen noch
> fehlender Ahnung) fällt es mir auch schwer, alles in eine Stored
> Procedure oder in Trigger auszulagern.

Ist IMHO auch nicht nötig. Dafür gibt es ja eben die

> Meine Frage ist eigentlich:
> Wie stelle ich es an, eine Transaktion mit mehreren SQL-Befehlen
> abzusenden, wenn jeder SQL-Befehl eine eigene Verbindung hat? Oder habe
> ich hier nur noch einen RTFM-Fehler und es geht doch?

Keine Ahnung. Aber möglich wär's ;)

Grüße,
Dominik

Re: Transaction - aber wie?

am 15.05.2007 23:35:25 von Axel Schwenke

Andreas Horn wrote:
>
> ich habe folgende Konstruktion:
> Client mit Webzugriff -> Apache/PHP -> MySQL/InnoDB.
> Generator ist CodeChargeStudio (http/mysql).

Habe ich noch nie von gehört. Klingt aber so, als wäre das das Problem.

> Ich möchte gerne Transaktionen verwenden. Dazu starte ich eine
> Verbindung (connect), kann aber mit immer nur 1 SQL-Befehl absetzen.
> Danach wird (bei nicht-permanenter Verbindung) die Verbindung beendet
> und zum Absetzen eines neuen SQL-Befehls eine neue Verbindung aufgebaut.

Aha. Irgendwie machen das alle anderen nicht so.

> Jetzt bin ich unsicher, ob eine Transaktion nur innerhalb einer
> Verbindung ablaufen kann, wie sollte sonst das DBMS wissen, ob von
> diesem Client ein weiterer zu dieser Transaktion gehörender SQL-Befehl
> kommt?

Eben deswegen macht man seine Datenbankverbindung erst nach dem letzten
SQL-Statement wieder zu. Und tatsächlich werden offene Transaktionen
abgebrochen (ROLLBACK) wenn der Client die Verbindung schließt.

> Wie stelle ich es an, eine Transaktion mit mehreren SQL-Befehlen
> abzusenden, wenn jeder SQL-Befehl eine eigene Verbindung hat?

Gar nicht.

Und nur für den Fall, daß ich dich mißverstanden habe: eine Datenbank-
Transaktion kann man nicht über mehrere HTTP-Seitenaufrufe verteilen.
Also theoretisch könnte man (mit persistenten Verbindungen), aber es
ist eine *ganz* schlechte Idee.


XL

Re: Transaction - aber wie?

am 16.05.2007 00:21:22 von Guido Schmidt

Andreas Horn schrieb:

> Generator ist CodeChargeStudio (http/mysql).

In der Doku findet sich eine Methode $datenbankObjekt->query() zum=20
Absetzen von SQL-Statements, die sich sicher mehrfach aufrufen lässt un=
d=20
somit Transaktionen grundsätzlich ermöglicht.
http://docs.codecharge.com/studio31/html/Components/Methods/ PHP/query.htm=
l

Allerdings habe ich zumindest auf die Schnelle nichts gefunden, um das=20
Ergebnis schreibender Queries zu prüfen? Ich weiß nicht, ob=20
CodeChargeStudio das geeignete Entwicklungswerkzeug ist, wenn Du=20
wirklich Transaktionen brauchst.

Guido

Re: Transaction - aber wie?

am 16.05.2007 09:01:22 von Christian Kirsch

Dominik Echterbruch schrieb:
> Andreas Horn schrieb:
> Damit hast du dir die Frage selber beantwortet :) AFAIK ist eine
> Transaktion immer an eine Verbindung gebunden (lustiger Satz) und wird
> automatisch mit einem ROLLBACK beendet, wenn die Verbindung ohne
> explizites COMMIT abbricht.
>

Es sei denn, auto_commit ist gesetzt. Dann ist die Transaktion mit dem
Unterbrechen der Verbindung automatisch ausgeführt.


>> Meine Frage ist eigentlich:
>> Wie stelle ich es an, eine Transaktion mit mehreren SQL-Befehlen
>> abzusenden, wenn jeder SQL-Befehl eine eigene Verbindung hat? Oder habe
>> ich hier nur noch einen RTFM-Fehler und es geht doch?

Natürlich "hat" nicht jeder SQL-Befehl eine eigene Verbindung.
Möglicherweise ist Dein Framework so geschrieben, dass es für jeden
SQL-Befehl eine Verbindung herstellt und sie direkt danach wieder
beendet. Dann solltest Du es vielleicht wechseln.

Re: Transaction - aber wie?

am 16.05.2007 09:50:36 von Robert Klemme

On 15.05.2007 23:35, Axel Schwenke wrote:
> Und nur für den Fall, daß ich dich mißverstanden habe: eine Datenbank-
> Transaktion kann man nicht über mehrere HTTP-Seitenaufrufe verteilen.
> Also theoretisch könnte man (mit persistenten Verbindungen), aber es
> ist eine *ganz* schlechte Idee.

Nicht nur mit persistenten Verbindungen sondern auch mit
Session-Management und serverseitigem Halten der Verbindung. Ist
kompliziert und fehleranfällig und man muss sich überlegen, was
passiert, wenn kein Request mehr folgt. Aber ich gebe dir Recht: es
*ist* eine schlechte Idee.

Ciao

robert

Re: Transaction - aber wie?

am 16.05.2007 18:56:51 von Claus Reibenstein

Christian Kirsch schrieb:

> Dominik Echterbruch schrieb:
>
>> Damit hast du dir die Frage selber beantwortet :) AFAIK ist eine
>> Transaktion immer an eine Verbindung gebunden (lustiger Satz) und wird
>> automatisch mit einem ROLLBACK beendet, wenn die Verbindung ohne
>> explizites COMMIT abbricht.
>
>
> Es sei denn, auto_commit ist gesetzt. Dann ist die Transaktion mit dem
> Unterbrechen der Verbindung automatisch ausgeführt.
>


Sicher?

Meines Wissens bedeutet ein gesetztes AUTO_COMMIT lediglich, dass
einzelne Befehle sofort ausgeführt werden und ich daher Transaktionen
explizit mit BEGIN einleiten muss. Ohne CONFIRM erfolgt bei einem
Verbindungsabbruch in jedem Fall ein ROLLBACK, wenn eine Transaktion
noch nicht abgeschlossen wurde.

Gruß. Claus

Lösung zu: Transaction - aber wie?

am 18.05.2007 10:01:23 von Andreas Horn

Andreas Horn schrieb:
> Hallo ng,
>
> ich habe folgende Konstruktion:
> Client mit Webzugriff -> Apache/PHP -> MySQL/InnoDB.
> Generator ist CodeChargeStudio (http/mysql).
> Ich möchte gerne Transaktionen verwenden. Dazu starte ich eine
> Verbindung (connect), kann aber mit immer nur 1 SQL-Befehl absetzen.
> Danach wird (bei nicht-permanenter Verbindung) die Verbindung beendet
> und zum Absetzen eines neuen SQL-Befehls eine neue Verbindung aufgebaut.
> Jetzt bin ich unsicher, ob eine Transaktion nur innerhalb einer
> Verbindung ablaufen kann, wie sollte sonst das DBMS wissen, ob von
> diesem Client ein weiterer zu dieser Transaktion gehörender SQL-Befehl
> kommt? Wegen der programmgesteuerten Auswertung (und auch wegen noch
> fehlender Ahnung) fällt es mir auch schwer, alles in eine Stored
> Procedure oder in Trigger auszulagern.
>
> Meine Frage ist eigentlich:
> Wie stelle ich es an, eine Transaktion mit mehreren SQL-Befehlen
> abzusenden, wenn jeder SQL-Befehl eine eigene Verbindung hat? Oder habe
> ich hier nur noch einen RTFM-Fehler und es geht doch?
>
> Danke schon mal
> Andreas

Eureka!

Da ich mit InnoDB auf MySQL 5.1 arbeite scheint "Stored Procedure" mein
Freund zu sein. Damit denke ich nur 1 SQL-Befehl absetzen zu müssen, der
Rest sollte in SP verpackt werden.

Vielen Dank für die Anregungen.

Dank auch besonders an
Stored Pocedures un MySQL 5 - Christoph Bichlmeier
http://www.tutorials.de/forum/sql-tutorials/179510-stored-pr ocedures-mysql-5-a.html

und
http://www.infos24.de/mysqle/handbuch/mysql_inhaltsverzeichn is.htm
http://www.aspheute.com/artikel/20020903.htm

Andreas
--
lesen bildet

Re: Lösung zu: Transaction - aber wie?

am 18.05.2007 14:03:18 von Robert Klemme

On 18.05.2007 10:01, Andreas Horn wrote:
> Andreas Horn schrieb:
>> Hallo ng,
>>
>> ich habe folgende Konstruktion:
>> Client mit Webzugriff -> Apache/PHP -> MySQL/InnoDB.
>> Generator ist CodeChargeStudio (http/mysql).
>> Ich möchte gerne Transaktionen verwenden. Dazu starte ich eine
>> Verbindung (connect), kann aber mit immer nur 1 SQL-Befehl absetzen.
>> Danach wird (bei nicht-permanenter Verbindung) die Verbindung beendet
>> und zum Absetzen eines neuen SQL-Befehls eine neue Verbindung aufgebaut.
>> Jetzt bin ich unsicher, ob eine Transaktion nur innerhalb einer
>> Verbindung ablaufen kann, wie sollte sonst das DBMS wissen, ob von
>> diesem Client ein weiterer zu dieser Transaktion gehörender SQL-Befehl
>> kommt? Wegen der programmgesteuerten Auswertung (und auch wegen noch
>> fehlender Ahnung) fällt es mir auch schwer, alles in eine Stored
>> Procedure oder in Trigger auszulagern.
>>
>> Meine Frage ist eigentlich:
>> Wie stelle ich es an, eine Transaktion mit mehreren SQL-Befehlen
>> abzusenden, wenn jeder SQL-Befehl eine eigene Verbindung hat? Oder habe
>> ich hier nur noch einen RTFM-Fehler und es geht doch?
>>
>> Danke schon mal
>> Andreas
>
> Eureka!
>
> Da ich mit InnoDB auf MySQL 5.1 arbeite scheint "Stored Procedure" mein
> Freund zu sein. Damit denke ich nur 1 SQL-Befehl absetzen zu müssen, der
> Rest sollte in SP verpackt werden.

Mir ist nicht so ganz klar, warum SP's hier die Lösung sein sollen.
Klar, du kannst in einer SP beliebig viele Statements absetzen - aber
das kannst du transaktionssicher mit einer DB-Verbindung auch
(autoCommit aus). Dein Problem war doch (so habe ich es zumindest
verstanden), dass deine DB-Operationen auf mehrere Web-Requests verteilt
sind. Dabei hilft dir eine SP gar nichts. Kannst du das erklären?

Ciao

robert

Re: Lösung zu: Transaction - aber wie?

am 18.05.2007 21:50:45 von Andreas Horn

Hallo Robert,

der von mir verwendete objektorientierte Generator "CodeCharge Studio"
erzeugt Templates und den PHP-Code. In diesem PHP-Code wird (so wie ich
ihn verwende) jedes mal beim Speichern eines neuen oder geänderten
Datensatzes eine Verbindung zur Datenbank hergestellt, der Insert- oder
der Update-SQL-Befehl abgesetzt und dann die Verbindung wieder
geschlossen. Jetzt gibt es aber das so genannte "Last Wins"-Problem. Das
stellt sich folgendermaßen dar:

Mittels Browserzugriff ruft User 1 einen Datensatz zum Ändern auf und
wird mittendrin unterbrochen. Inzwischen ruft User 2 denselben Datensatz
ebenfalls zum Ändern auf und speichert ihn ab. Danach kommt User 1
endlich dazu seine Version des Datensatzes zu speichern. Jetzt wird die
von User 2 vorgenommene Änderung mit den Werten, die von User 1
eingegeben wurden, überschrieben - und keiner weiß was davon.

Wenn ich diesen Problem richtig vermeiden will - und keine Verklemmung
durch Sperrung und Schließen des Browsers ohne Aufhebung der Sperrung
riskieren will - muss ich mir bei einem verbindungslosen Protokoll wie
http oder https etwas einfallen lassen.


Deshalb wird in jeder Tabelle der Loginname und die Änderungs-Datetime
mit gespeichert. Beim Lesen des Datensatzes werden diese Werte ebenfalls
ausgelesen. Soll nach Änderung des Datensatzes jetzt gespeichert werden,
wird eine Stored Procedure angestoßen. Diese soll jetzt folgendes leisten:

Der Stored Procedure werden beim Aufruf die vorher aus dem Datensatz
gelesenen Werte für Loginname und Änderungs-Datetime mitgegeben.
Eine Transaktion starten.
Die Werte für Loginname und Änderungs-Datetime dieses Datensatzes erneut
aus der Tabelle lesen.
Vergleichen der jetzt gelesenen Werte für Loginname und
Änderungs-Datetime mit denen die der SP beim Aufruf mitgegeben wurden.
Sind die Werte noch gleich, wurde der Datensatz noch nicht geändert.
Update und Commit kann erfolgen. Gleichzeitig wird eine Rückgabevariable
auf "Erfolgreich" gesetzt.
Sind die Werte NICHT gleich, wurde der Datensatz inzwischen geändert, es
erfolgt ein Rollback und die Rückgabevariable wird auf "Fehlgeschlagen"
gesetzt.
Die SP ist jetzt beendet.

Im PHP-Skript kann jetzt die Rückgabevariable ausgewertet werden und der
Benutzer erhält beim Fehlschlagen einen Hinweis, dass der Datensatz
zwischenzeitlich geändert wurde.

Ich hoffe, ich habe mich verständlich ausgedrückt - und dass es auch so
funktioniert, wie ich es mir denke. Falls ich hier noch einen Denkfehler
habe, bitte schnell her damit!

Mit freundlichen Grüßen
Andreas
--
lesen bildet

Re: Lösung zu: Transaction - aber w ie?

am 19.05.2007 00:35:25 von Siegfried Schmidt

Hallo Andreas,

> Der Stored Procedure werden beim Aufruf die vorher aus dem Datensatz
> gelesenen Werte für Loginname und Änderungs-Datetime mitgegeben.
> Eine Transaktion starten.
> Die Werte für Loginname und Änderungs-Datetime dieses Datensatzes
> erneut aus der Tabelle lesen.
> Vergleichen der jetzt gelesenen Werte für Loginname und
> Änderungs-Datetime mit denen die der SP beim Aufruf mitgegeben wurden.
> Sind die Werte noch gleich, wurde der Datensatz noch nicht geändert.
> Update und Commit kann erfolgen. Gleichzeitig wird eine
> Rückgabevariable auf "Erfolgreich" gesetzt.

Das gleiche leistet ein einfaches Update, wenn als Bedingung zusätzlich der
ursprüngliche Zeitstempel angegeben wird.

Der Umweg über eine SP mit zusätzlicher Abfrage ist total überflüssig. Sie
funktioniert in der angegebenen Form auch nicht, da du eine Stored Function einsetzen
willst, in der Transaktionen nicht möglich sind.


Siegfried
--
http://www.schmidt.ath.cx

Re: Lösung zu: Transaction - aber w ie?

am 19.05.2007 09:30:56 von Andreas Horn

Siegfried Schmidt schrieb:

> ...
> funktioniert in der angegebenen Form auch nicht, da du eine Stored Function einsetzen
> willst, in der Transaktionen nicht möglich sind.
> ...

Es ist nur für Stored Function richtig, dass die mein Problem nicht
lösen. Bei Stored Procedure kann jeder Parameter als IN (=default), OUT
oder INOUT gesetzt werden. Ich muss nur nach sehen, wie das mit den
Variablen im SQL-Aufruf CALL() funktioniert.

> ...
> Das gleiche leistet ein einfaches Update, wenn als Bedingung
zusätzlich der
> ursprüngliche Zeitstempel angegeben wird.
> ...

Das ist vermutlich DIE Idee, werde ich mal intensiv drüber nachdenken.
Vielen Dank für diesen Tipp!

mfg
Andreas

Re: Lösung zu: Transaction - aber wie?

am 19.05.2007 10:31:50 von pkoeker

Andreas Horn schrieb:
[...]
Herzlichen Glückwunsch!
Da hast das optimistische Locking entdeckt!

Dieses wird am einfachsten wie folgt implementiert:
Die Tabelle erhält ein zusätzliches Feld "Version" (BIGINT not null
default 0).
Dieses Feld wird bei jedem Update um eins erhöht, wenn es in der
Zwischenzeit nicht verändert wurde:

UPDATE ... SET version = $version+1 WHERE version = $version ...

Wenn dieses Update mißlingt kann man anhand der Fehlermeldung ermitteln
woran es lag (es muß ja nicht der Versionszähler gewesen sein).

Denkbare Erweiterung:
Zur Information den Namens des Users/IP-Adresse, Timestamp mit speichern.

Weit verbreitete Mythen/Gerüchte:
- Der Versionszähler kann nicht überlaufen; selbst bei 1000
Updates/Sekunde reicht er 300Mio Jahre.
- Ein Timestamp statt Versionsähler ist keine gute Idee, da nicht
sichergestellt ist, daß sich die Zeit immer nur in eine Richtung bewegt
und manche Betriebssystem die Zeit nicht unter 20ms auflösen können.

Gruß, Peter

Re: Lösung zu: Transaction - aber wie?

am 20.05.2007 17:28:33 von Dirk Brosowski

Andreas Horn schrieb:
>
> Eureka!
>
> Da ich mit InnoDB auf MySQL 5.1 arbeite scheint "Stored Procedure" mein
> Freund zu sein. Damit denke ich nur 1 SQL-Befehl absetzen zu müssen, der
> Rest sollte in SP verpackt werden.
>

Ich bin nicht deiner Meinung, dass du die Lösung gefunden hast. Du hast
einen Workaround gefunden.

Die Lösung wäre es dieses offensichtlich total übeforderte "Framework"
durch etwas besseres abzulösen. Und das es sowas gibt ist sicher, denn
auch PHP ist nicht total hinter dem Mond.

Viele Grüße

Dirk

Re: Lösung zu: Transaction - aber wie?

am 21.05.2007 12:16:58 von Andreas Horn

Peter Köker schrieb:

> Herzlichen Glückwunsch!
> Da hast das optimistische Locking entdeckt!

Danke, aber diese Ohrfeige habe ich wohl ein klein wenig verdient.

> Die Tabelle erhält ein zusätzliches Feld "Version" (BIGINT not null
> default 0).
> Dieses Feld wird bei jedem Update um eins erhöht, wenn es in der
> Zwischenzeit nicht verändert wurde:
>
> UPDATE ... SET version = $version+1 WHERE version = $version ...
>
> Wenn dieses Update mißlingt kann man anhand der Fehlermeldung ermitteln
> woran es lag (es muß ja nicht der Versionszähler gewesen sein).

Besonderen Dank für die Syntax, da brauche ich jetzt nicht mehr viel
weiterzulesen. Außerdem ist bei mir jetzt endlich der Groschen
gerutscht, wie das mir der Versionierung genau funktioniert (wurde auch
langsam Zeit).

mfg
Andreas

Re: Lösung zu: Transaction - aber wie?

am 21.05.2007 12:25:45 von Andreas Horn

Dirk Brosowski schrieb:

> Die Lösung wäre es dieses offensichtlich total übeforderte "Framework"
> durch etwas besseres abzulösen. Und das es sowas gibt ist sicher, denn
> auch PHP ist nicht total hinter dem Mond.

Hallo Dirk,

ich habe mir auch schon verschiedene CMS angesehen, aber die
Einarbeitungszeit ist meist auch nicht unerheblich. Und das was ich
brauche ist oft nicht abbildbar (n:m-Beziehung einer Tabelle mit sich
selbst, klingt vielleicht doof, habe aber dafür meine - sicher nicht
optimale - Lösung gefunden). Leider bleibt nicht die Zeit, alles
auszuprobieren, da muß man schon Hinweise von Anderen zur Selektion
nutzen - und irgendwann in meinem Leben will ich auch mal fertig werden.

Was wäre denn Dein Favorit statt "CodeCharge Studio"?

mfg
Andreas

Re: Lösung zu: Transaction - aber wie?

am 21.05.2007 22:48:29 von Dirk Brosowski

Andreas Horn schrieb:
> Dirk Brosowski schrieb:
>
>> Die Lösung wäre es dieses offensichtlich total übeforderte "Framework"
>> durch etwas besseres abzulösen. Und das es sowas gibt ist sicher, denn
>> auch PHP ist nicht total hinter dem Mond.
>
> Hallo Dirk,
>
> ich habe mir auch schon verschiedene CMS angesehen, aber die
> Einarbeitungszeit ist meist auch nicht unerheblich. Und das was ich
> brauche ist oft nicht abbildbar (n:m-Beziehung einer Tabelle mit sich
> selbst, klingt vielleicht doof, habe aber dafür meine - sicher nicht
> optimale - Lösung gefunden). Leider bleibt nicht die Zeit, alles
> auszuprobieren, da muß man schon Hinweise von Anderen zur Selektion
> nutzen - und irgendwann in meinem Leben will ich auch mal fertig werden.
>
> Was wäre denn Dein Favorit statt "CodeCharge Studio"?

Als Nicht-PHP-ler kann ich dir das nicht für PHP nicht sagen. Ich weiss
nur, dass das Framework "unterbelichtet" zu sein scheint ...

Grüße

Dirk