# Theorie : Mehrer Threads - Commit  (MySQL)



## Tallan (22. Okt 2009)

Hallo zusammen,

folgedner Fall :

in einem Programm laufen 2 Treads A und B.
A und B schreiben jeweils etwas in die Datenbank ( unterschiedliche Tabellen )
Es werden PreparedStatement erstellt und dann einen Commit ausgeführt.
Das Programm selbst hat nur eine Datenbankverbindung.

Gehe ich richtig in der Annahme das wenn Thread A einen Commit über die DB-Verbindung ausführt die Anweisungen von B auch ausgeführt werden?
Falls ja, gibt es einen weg das abzusichern ohne auf Threads zu verzichten und ohne eine 2te Datenbankverbindung zu erstellen?


----------



## MrWhite (22. Okt 2009)

Sowas nennt sich Race-Condition und kann vorkommen, wenn Thread1 den commit macht wenn Thread 2 den Query schon abgeschickt hat aber noch nicht comitted hat.

Ob das vorkommen kann, hängt eher vom Treiber ab. Es könnte schon sein, dass es da zu ganz anderen Problemen kommt oder das Problem schon bedacht wurde.

Am besten hat jeder Thread seine eigene Connection oder du deklarierst die Methode, die Queries ausführt als synchronized.


----------



## tfa (22. Okt 2009)

Tallan hat gesagt.:


> Gehe ich richtig in der Annahme das wenn Thread A einen Commit über die DB-Verbindung ausführt die Anweisungen von B auch ausgeführt werden?


Ja.


> Falls ja, gibt es einen weg das abzusichern ohne auf Threads zu verzichten und ohne eine 2te Datenbankverbindung zu erstellen?


Nein.


----------



## MrWhite (22. Okt 2009)

tfa hat gesagt.:


> Ja.
> 
> Nein.



tfa, mit deiner zweiten Aussage liegst du falsch. Schonmal was von *synchronized* gehoert?

Wie waere es mit einem threadsicheren Queue fuer Queries?


----------



## tfa (22. Okt 2009)

MrWhite hat gesagt.:


> tfa, mit deiner zweiten Aussage liegst du falsch. Schonmal was von *synchronized* gehoert?
> 
> Wie waere es mit einem threadsicheren Queue fuer Queries?



Was bekommt denn deine Datenbank von dem synchronized mit?
Wenn du auf der Connection commit aufrufst wird alles committet, egal welcher Thread welche Queries abgesetzt hat. Du kannst hier keine Transaktionen trennen.


----------



## MrWhite (22. Okt 2009)

Ich habe doch einen Weg beschrieben, das abzusichern. Ein threadsicherer Queue in den Queries gelegt werden z.B. und der irgendwann von einem Thread ausgefuehrt wird.

Gemaess der Fragestellung.


----------



## DamienX (23. Okt 2009)

Mal abgesehen davon dass ich noch nie jemanden bei Datenmanipulationen von
"Queries" sprechen habe hören...

1. Wenn sie auf unterschiedlichen Tabellen arbeiten ist es sowieso egal.
2. Selbst wenn die commits übereinanderlaufen wirst du auf einigermaßen
    namhaften Datenbanken niemals erleben dass sich daten "vermischen" oder
    sonstiges (Ich denke darauf zielte die Frage ab... wenn nicht... auch egal ;D )

-> Was allerdings passieren kann ist dass du zb einen Update machst... dieser noch nich durchgeführt
    wurde und aus deiner programmlogik einen erneuten Updatebefehl abgibts!

Dann sperrt der erste die Datensätze und der Zweite wartet bis Transaktion 1 durchgelaufen ist.
Dann macht Update 2 seine arbeit. 

Das kann evtl. nich gewollt sein aber liegt dann an der client Seite.


----------



## Unregistriert (24. Okt 2009)

DamienX hat gesagt.:


> Mal abgesehen davon dass ich noch nie jemanden bei Datenmanipulationen von
> "Queries" sprechen habe hören...



Das ist aber komisch. 20 000 000 google suchergebnisse die DML als queries bezeichnen, können sich nicht irren.


----------



## Tallan (9. Nov 2009)

gibt es diesbezüglich auch keine möglichkeit mit Transaktionen?
Die in Using Transactions (The Java™ Tutorials > JDBC(TM) Database Access > JDBC Basics) beschriebenen wurden nichts bringen.
Gibt es alternativ nicht eine möglichkeit mit Begin ... End ?


----------



## maki (9. Nov 2009)

> Falls ja, gibt es einen weg das abzusichern ohne auf Threads zu verzichten und ohne eine 2te Datenbankverbindung zu erstellen?


Warum willst du denn mehrere DB Verbindungen verhindern?
Ist sehr normal mehrere Verbindungen in einer Multithreaded App zu haben, auch als ConnectionPool bekannt.

Wenn du gutes Transaktionens- Management und -Deklaration willst solltest du dir Spring oder EJB ansehen.


----------



## Tallan (9. Nov 2009)

maki hat gesagt.:


> Warum willst du denn mehrere DB Verbindungen verhindern?
> Ist sehr normal mehrere Verbindungen in einer Multithreaded App zu haben, auch als ConnectionPool bekannt.
> 
> Wenn du gutes Transaktionens- Management und -Deklaration willst solltest du dir Spring oder EJB ansehen.



Verhindern möchte ich es nicht unbedingt ich wollte nur nicht unbedingt für jeden anweder eine extra DB-Con aufbauen zumal der zugriff auf die Datenbank nicht direkt von client ausgeführt wird sondern über eine middelware läuft


----------



## tfa (9. Nov 2009)

Tallan hat gesagt.:


> Verhindern möchte ich es nicht unbedingt ich wollte nur nicht unbedingt für jeden anweder eine extra DB-Con aufbauen zumal der zugriff auf die Datenbank nicht direkt von client ausgeführt wird sondern über eine middelware läuft



Gerade wenn du eine Middleware (bzw. Applicationserver) hast, brauchst du nicht so viele DB-Connections. Das kann alles der Server managen, je nachdem wie die Clientanfragen eintreffen.

Der Tipp mit dem Spring-Framework ist übrigens Gold wert. Hiermit brauchst du dich fast gar nicht mehr um Connection-Pooling und Transaktionsverwaltung kümmern. Jedenfalls ist nicht viel Handarbeit notwendig.


----------



## Gast2 (9. Nov 2009)

MrWhite hat gesagt.:


> Sowas nennt sich Race-Condition und kann vorkommen, wenn Thread1 den commit macht wenn Thread 2 den Query schon abgeschickt hat aber noch nicht comitted hat.


jain

Thread A - "select * from tabelle1"
Thread B - "update tabelle 2 SET ..."

das funktioniert super ohne das ich mich um etwas kümmern muss ... beide SQL-Statements sind für sich atomar ... die Datenbank hat sich hier darum zu kümmern das da nichts schief läuft ... wenn die DB das nicht macht - wegschmeißen die taugt nichts

holst Du Dir aber Daten aus der DB, machst damit eine Berechnung und dann wieder ein UPDATE mit den neuen Daten ... dann musst Du darauf achten das andere Threads nicht die Daten verhauen - Race Conditions (wurde aber schon erwähnt) ... allerdings bieten hierfür Treiber der gängige Datenbanken entsprechende Statements um auch mehrere SQL-Statements als atomar zu definieren - Transaction (wurde schon erwähnt) ... dazu mal die passenden Handbücher der Datenbanken lesen ... Du kannst aber auch auf Frameworks zugreifen die das Ganze abstrahiert haben - auf einfache Benutzung hin



> Am besten hat jeder Thread seine eigene Connection


macht keinen Sinn ... hier ist es egal ob Du mehrere Connections hast oder nur eine ... Du kannst auch mit 2 Connections eine Race Condition erhalten

hand, mogel


----------



## Tallan (9. Nov 2009)

mogel hat gesagt.:


> jain
> 
> Thread A - "select * from tabelle1"
> Thread B - "update tabelle 2 SET ..."
> ...



Atomare querrys sind kein Porblem.
Die Threads schreiben auch nicht auf den selben Datensätzen daher fällt die race condition auch raus.

Ein Beispiel zu dem Problem.

Thread A legt eine Zeile in mehreren Tabellen an die Aufeinander verweist hierfür setze ich wie im Tutorial beschrieben den autocommit auf false.. baue meine Statments fülle es mit Daten und commite dann.

In der Zwischenzeit will Thread B munter Atomare Operationen ausführen, sprich einzelne querrys ausführen.

Wenn ich für beide jetzt nur eine Connection hab kann folgendes passieren.

Entweder hat Thread B Autocommit an und kann somit die einzelnen Querrys raushauen, womit die Transaktion in A sinnlos ist da ja Autocommit an ist..

Oder Aber B hat autocommit aus, sendet seine Querrys, in Thread A funktioniert etwas nicht -> Rollback -> Rollback der Daten von B weil für die Querrys von B kein Commit stattfand.


Wenn ich 2 Connections nutzte hab ich kein Problem, die Frage ist allerdings ob es da eine Sinvolle alternative gibt, da es ja etwa mehr als nur 2 User sein werden.


Gedanken über einen Connection Pool und das Spring Framework werde ich mir machen, danke für die Tips


----------



## tfa (9. Nov 2009)

Was haben denn Threads damit zu tun? Die DB weiß nichts von Java-Threads. Hier zählen nur die Datenbank-Sessions, und die hängen an der Connection. Autocommits und Rollbacks werden auch an der Connection gemacht, nicht an Threads...

Entweder versteh ich euch nicht, oder ihr verwechselt was. ???:L


----------



## maki (9. Nov 2009)

> Gedanken über einen Connection Pool und das Spring Framework werde ich mir machen, danke für die Tips


Wenn du Spring nutzt, musst du dir keine (oder kaum) Gedanken mehr um solche Low-Level Probleme machen 

Da reicht ein [c]@Transactional[/c] um die Methoden zu markieren welche in einer Transaktion laufen soll.


----------



## Tallan (9. Nov 2009)

tfa hat gesagt.:


> Was haben denn Threads damit zu tun? Die DB weiß nichts von Java-Threads. Hier zählen nur die Datenbank-Sessions, und die hängen an der Connection. Autocommits und Rollbacks werden auch an der Connection gemacht, nicht an Threads...
> 
> Entweder versteh ich euch nicht, oder ihr verwechselt was. ???:L



threads in soweit das der zeitpunkt wann der commit stattfinden nicht festgelegt ist und auch keine reihenfolge haben muss


----------



## Gast2 (9. Nov 2009)

Tallan hat gesagt.:


> Thread A legt eine Zeile in mehreren Tabellen an die Aufeinander verweist hierfür setze ich wie im Tutorial beschrieben den autocommit auf false.. baue meine Statments fülle es mit Daten und commite dann.
> 
> In der Zwischenzeit will Thread B munter Atomare Operationen ausführen, sprich einzelne querrys ausführen.
> 
> [...]



ay caramba ... das dürfte wirklich an der Connection hängen

hand, mogel


----------

