Zwei Befehle gleichzeitig ausführen



  • Ich möchte gerne Daten in eine Zeile einer MySQL Tabelle einfügen. Dafür benutze ich die Syntax
    "PreparedStatement ps = con.prepareStatement("INSERT INTO fotos ( foto_id, user_id, image_path, image_thumbPath ) VALUES ( ?, ?, ?, ? )");"

    Anschließend möchte ich gerne die foto_id erfahren die die Datenbank erzeugt hat. Das mache ich mittels

    ResultSet rs = statement.executeQuery( "SELECT MAX( foto_id ) FROM fotos;" );

    Das benötige ich, da die fotoId auch gleichzeitig der Dateiname des Fotos sein soll.

    Leider sind das zwei Befehle auf einmal. Nun frage ich mich folgendes:
    Benutzer A fügt ein neues Foto ein und Benutzer B auch. B schreibt nach A. Dann fragt A nach der maximalen fotoId und erhält die von B. Das soll natürlich nicht passieren. Gibt es irgendwie die Möglichkeit die fotoId sofort zu ermitteln?





  • Lass die "foto_id" einfach nicht automatisch berechnen, sondern bastel dir selbst eine Sequenz.



  • Zu last_insert_id: Meine Clients benutzen alle dieselbe Verbindung zur Datenbank, so wie ich das in der Doku verstehe wäre das das gleiche was ich bis jetzt benutze. Soll heißen:
    Zwischen

    PreparedStatement ps = con.prepareStatement("INSERT INTO fotos ( foto_id, user_id, image_path, image_thumbPath ) VALUES ( ?, ?, ?, ? )");
    

    und

    ResultSet rs = statement.executeQuery( "SELECT MAX( foto_id ) FROM fotos;" );
    

    kann sich immer noch ein anderer Thread dazwischen schleichen. Also zB Thread A und B. A wird genau zwischen diesen beiden Befehlen unterbrochen und B arbeitet beide Befehle ab und A erhält schließlich dieselbe foto_id wie B. Das soll aber genau nicht passieren. Oder verstehe ich was falsch bei last_insert_id?



  • Ist es eigentlich zu teuer, für jeden Thread eine eigene Verbindung zu öffnen? Wenn ja kannst Du notfalls etwas eigenes bauen, eine Hilfstabelle mit einem Autoinkrement und einer Spalte für die Thread-PID. Dort diese PID einfügen, wieder auslesen, Autoinkrementwert verwenden.



  • Sollte man denn jeden Benutzer einer Webseiten eine eigene Verbindung zur DB zuweisen?



  • Warum denn nicht? Bei OLTP wäre es evtl interessanter, Connection Pooling einzusetzen.



  • Zur Zeit sieht es so aus, dass ein Nutzer nach der Anmeldung eine Datenbankverbindung bekommt (Erzeugen einer neuen Verbindung zur DB) und diese dann im Session-Objekt des Webservers (Tomcat) abgelegt wird. Fordert der Nutzer Daten vom Server an, wird das zum Benutzer gehörende Datenbank-Objekt aus dem Session-Objekt genommen und damit auf die Datenbank zugegriffen. D.h. es wird eine Verbindung zu DB beim Einloggen aufgebaut und anschließend wird diese Verbindung bis zum Ablauf der Session oder Abmelden des Nutzers aufrecht gehalten. Ich frage mich ob das effizient ist, oder ob eine andere Herangehensweise vielleicht besser wäre?

    1. Man könnte das doch noch mittels Connection Pooling erweitern und somit verbessern?
    2. Was genau ist OLTP? Ich kann mir unter den Definitionen die Google ausspuckt nicht viel vorstellen.



  • OLTP=online transaction processing

    tomatensalat schrieb:

    Sollte man denn jeden Benutzer einer Webseiten eine eigene Verbindung zur DB zuweisen?

    Normalerweise macht man das entweder so, oder man macht gleich eine neue Connection pro Page-Load.
    In beiden Fällen kann man Connection-Pools verwenden wenn es ohne zuviel Overhead wäre.

    EDIT: pro Page-Load hat oft enorme Vorteile wenn viele User (sagen wir mal 1000 oder so) gleichzeitig eingeloggt sein werden, da man dann nicht pro User eine Connection braucht, sondern nur pro gleichzeitig verarbeitetem Request. /EDIT

    Wenn man eine Connection für alle verwendet können nicht nur in dem von dir skizzierten Fall Fehler passieren, sondern auch etliche andere Dinge Schief Gehen (tm).
    z.B. kannst du Transaktionen gleich mal vergessen, lokale Temp-Tables, Variablen, ...



  • tomatensalat schrieb:

    Sollte man denn jeden Benutzer einer Webseiten eine eigene Verbindung zur DB zuweisen?

    Wenn man Transaktionen verwenden will/muß, dann ist das der einzig sinnvolle Weg. Dein Problem wäre (keine Ahnung wie es mit last_insert_id aussieht, ein richtiges RDBMS hat Sequenzen) mit einer Transaktion aus der Welt.


Anmelden zum Antworten