Disaster: SELECT und UPDATE parallel ausführen?

Hallo!

ich habe ein Problem mit einem Select und Update Statement.

Unzwar habe ich eine DB in der laufen neue Einträge hinzukommen. Und es gibt Clients, die sich immer einzelne Einträge abholen. Aber immer nur einen. Nun darf aber kein Eintrag an zwei Clients gesendet werden.

Deswegen habe ich nun ein STATUS Feld eingeführt, was nach dem select durch eine UPDATE Query auf 1 gesetzt wird. Das Problem ist, dass die beiden Befehle nacheinander ausgeführt werden und es somit schon vorgekommen ist, dass zwei Clients die gleiche AW bekommen haben.

Gibt es eine Möglichkeit SELECT und Update als ein StateMent auszuführen?

Disaster

  1. Hi,

    Gibt es eine Möglichkeit SELECT und Update als ein StateMent auszuführen?

    nein. Allerdings gibt es je nach DBMS ein SELECT FOR UPDATE. Näheres findest Du entweder in der Dokumentation Deines DBMS, oder es beherrscht dies vermutlich nicht.

    Cheatah

    --
    X-Will-Answer-Email: No
    1. Sorry, es geht um MySQL

      Disaster

      1. Hi,

        Sorry, es geht um MySQL

        und was hast Du in dessen Doku gefunden?

        Cheatah

        --
        X-Will-Answer-Email: No
        1. Hallo Cheatah,

          was issn:

          » X-Will-Answer-Email: No

          Viele Grüße aus dem Süden, Frank

          1. Hi,

            was issn:
            » X-Will-Answer-Email: No

            der Hinweis darauf, dass ich auf Rückfragen per Mail nicht eingehe. Ich habe - leider! - die Erfahrung machen müssen, dass so mancher eine Hilfestellung als Einwilligung in kostenlosen Support fehlinterpretiert...

            Cheatah

            --
            X-Will-Answer-Email: No
            1. Hallo,

              was issn:
              » X-Will-Answer-Email: No

              der Hinweis darauf, dass ich auf Rückfragen per Mail nicht eingehe. Ich habe - leider! - die Erfahrung machen müssen, dass so mancher eine Hilfestellung als Einwilligung in kostenlosen Support fehlinterpretiert...

              ich muß zugeben, dass auch nicht verstanden zu haben, bist jetzt. Um die Sache eindeutiger zu gesatlten, wie wär's denn mit "Rufen Sie mich nicht an, ich rufe Sie ja auch nicht an"
              oder
              "Bitte haben Sie etwas Geduld, ich schicke Ihnen ein Script" *g*

              scnr
              achim

            2. Halihallo Cheatah

              was issn:
              » X-Will-Answer-Email: No

              der Hinweis darauf, dass ich auf Rückfragen per Mail nicht eingehe. Ich habe - leider! - die Erfahrung machen müssen, dass so mancher eine Hilfestellung als Einwilligung in kostenlosen Support fehlinterpretiert...

              Nach, bei mir kamen auch schon ein, zwei bettelnd in die Mailbox. Es gibt nix schöneres, als sich die Mails auf der Zunge vergehen zu lassen und mit einem (kalten): "ich bin bereit, dir im forum.de.selfhtml.org zu helfen, aber zum eigenen Schutz verzichte ich auf das Antworten per E-Mail."... zu antworten.

              Ist es nicht schön, wenn man gebraucht wird :-))

              Viele Grüsse

              Philipp

              1. Moin!

                Nach, bei mir kamen auch schon ein, zwei bettelnd in die Mailbox. Es gibt nix schöneres, als sich die Mails auf der Zunge vergehen zu lassen und mit einem (kalten): "ich bin bereit, dir im forum.de.selfhtml.org zu helfen, aber zum eigenen Schutz verzichte ich auf das Antworten per E-Mail."... zu antworten.

                s/zu antworten/per Autoreply antworten zu lassen/

                :)

                - Sven Rautenberg

                --
                Diese Signatur gilt nur am Freitag.
                1. Halihallo Sven

                  Nach, bei mir kamen auch schon ein, zwei bettelnd in die Mailbox. Es gibt nix schöneres, als sich die Mails auf der Zunge vergehen zu lassen und mit einem (kalten): "ich bin bereit, dir im forum.de.selfhtml.org zu helfen, aber zum eigenen Schutz verzichte ich auf das Antworten per E-Mail."... zu antworten.

                  s/zu antworten/per Autoreply antworten zu lassen/

                  :)

                  Stimmt. Das kommt noch viel besser. "ICH BIN WICHTIG! - JEDE
                  "SAU" SPRICHT MIT MIR" jetzt auch noch impliziert ;)
                  ^^^^^ so steht's doch im Song-Text, oder? - "Keine Sau ruft mich an :-(( ..."

                  Viele Grüsse

                  Philipp

            3. Hallo, Hajo,

              was issn:
              » X-Will-Answer-Email: No

              der Hinweis darauf, dass ich auf Rückfragen per Mail nicht eingehe. Ich habe - leider! - die Erfahrung machen müssen, dass so mancher eine Hilfestellung als Einwilligung in kostenlosen Support fehlinterpretiert...

              Achso.

              Das verstehe ich, solche Mails bekomme ich auch von Zeit zu Zeit, da es bisher nur Mails von Menschen waren, welche sich bereits intensiv mit dem Archiv auseinandergesetzt haben und dadurch auf meine Postings und meine Netzpostadresse gestoßen sind, habe ich mir die Zeit genommen, zu antworten. Ein anderer Fall ist, dass ein Thread im Archiv gelandet ist und der OP nicht zeitnah einen neuen Thread mit einer Folgefrage öffnen will; wenn es sowieso ein Follow-Up auf mein Posting ist und die weitere Diskussion für die Öffentlichkeit wenig aufschlussreich oder interessant ist, ist eine Mail das einzig Richtige, um nicht die Bandbreite anderer Leute zu schmälern... IMHO.

              Bisher dachte ich, dass du damit meinst, dass du gar nicht auf E-Mails antwortest... (nein, nicht wirklich... ;)) Erinnert an Usenet-Adressfälscher oder diejenigen, die Mails an die From-Adresse sofort in die Tonne kloppen und nur Mails an die Reply-To-Adresse lesen, wobei letzteres sicherlich legitim ist; wie auch immer, es wäre unlogisch, da du hier nicht gezwungen bist, überhaupt eine Adresse anzugeben...

              Ich hoffe und denke schon, dass du entgegen des Headers auf E-Mails antwortest, *g* deshalb ist der Header wohl ein wenig pauschal formuliert, ob er überhaupt seine Wirkung erfüllt ist wohl fragwürdig, auf einen eventuellen Fragesteller, der gedenkt, dir eine Mail zu schreiben, hat er meiner Meinung nach in dieser Form wenig Wirkung, aber sofern es für dich hilft, ist es zweifellos angemessen...

              "Blabla"...

              Mathias

              --
              "Die größten Kritiker der Elche waren früher selber welche"
              (Prof. Fritz Weigle alias F. W. Bernstein)
              "Wie ein gefoppter Nachtmahr der auf Tücke sinnt..." (Hugo Ball, "Die Katze")
        2. » »» Sorry, es geht um MySQL

          und was hast Du in dessen Doku gefunden?

          Leider nicht passendes habe nur ein kombiniertes SELECT, INSET gefunden.

          Disaster

  2. Hi,

    Unzwar habe ich eine DB in der laufen neue Einträge hinzukommen. Und es gibt Clients, die sich immer einzelne Einträge abholen. Aber immer nur einen. Nun darf aber kein Eintrag an zwei Clients gesendet werden.

    Deswegen habe ich nun ein STATUS Feld eingeführt, was nach dem select durch eine UPDATE Query auf 1 gesetzt wird. Das Problem ist, dass die beiden Befehle nacheinander ausgeführt werden und es somit schon vorgekommen ist, dass zwei Clients die gleiche AW bekommen haben.

    Gibt es eine Möglichkeit SELECT und Update als ein StateMent auszuführen?

    nicht daß ich wüßte, hängt aber vielleicht auch vom DB-System ab. Du verrätst die wesentliche Information ja leider nicht, welches DB-System Du benutzt.
    Du könntest es mit Transaktionen und Locking nachzubilden probieren, sofern Dein DB-System das zuläßt.

    cu,
    Andreas

    1. Sorry, es geht um MySQL

      Disaster

      1. Hi Disaster,

        Sorry, es geht um MySQL

        ja, und?

        Transaktionen sind Eigenschaften von Tabellentreibern,
        nicht von Datenbanken an sich.

        Viele Grüße
              Michael

        1. Halihallo Transaktionsfreunde

          Sorry, es geht um MySQL

          ja, und?

          Transaktionen sind Eigenschaften von Tabellentreibern,
          nicht von Datenbanken an sich.

          http://www.mysql.com/news/article-113.html
          http://www.mysql.com/doc/en/Table_types.html, nur um mal kurz genannt zu sein...

          auch mysql hat den Umstieg geschafft :-)
          Naja, Views sollten ja auch in Version 5.0 implementiert sein. Was fehlt dann noch? - Stored Procedures, ja... Also ich liebe mysql! :-)

          Viele Grüsse

          Philipp

  3. Hallo Disaster,

    Du kannst Transaktionen verwenden. Das unterstüzt mittlerweile auch MySQL.
    Die Datenbank sorgt dafür, dass die Daten sich wärend einer Transaktion nicht ändern.

    http://www.mysql.com/documentation/mysql/bychapter/manual_Reference.html#Transactional_Commands

    Grüße

    Daniel

  4. Moin!

    Hallo!

    ich habe ein Problem mit einem Select und Update Statement.

    Unzwar habe ich eine DB in der laufen neue Einträge hinzukommen. Und es gibt Clients, die sich immer einzelne Einträge abholen. Aber immer nur einen. Nun darf aber kein Eintrag an zwei Clients gesendet werden.

    Deswegen habe ich nun ein STATUS Feld eingeführt, was nach dem select durch eine UPDATE Query auf 1 gesetzt wird. Das Problem ist, dass die beiden Befehle nacheinander ausgeführt werden und es somit schon vorgekommen ist, dass zwei Clients die gleiche AW bekommen haben.

    Gibt es eine Möglichkeit SELECT und Update als ein StateMent auszuführen?

    Ändere deine Datenbankstrategie!

    Was du brauchst, ist eine atomare Operation in der Datenbank. Das kann natürlich mit Transaktionen klappen (die verbinden mehrere einzelne Operationen zu einer quasi-atomaren Operation). Aber im Prinzip hast du "nur" folgendes Problem: Du mußt einen einzigen Datensatz der vorhandenen Tabelle so kennzeichnen, dass er in der Folge nur von einem Client bearbeitet werden kann.

    Und diese Operation heißt "UPDATE". :) Ein einzelnes Update klappt immer, ohne dass es von anderen Updates oder Selects beeinflußt wird.

    Also: Deine Kennzeichnung des Datensatzes für den Client muß diesen eindeutig kennzeichnen. Dazu benötigst du sehr wahrscheinlich noch die eine oder andere Spalte zusätzlich in deiner Datenbank.

    Ich stelle mir die Sache so vor: Deine Datentabelle enthält (neben den Spalten für die Daten) noch mindestens eine Spalte für den Bearbeitungsstatus und eine Spalte für eine Client-ID, die den Client eindeutig identifiziert, der den jeweiligen Eintrag bearbeitet.

    Beispiel:
    ID   Status   CID  Daten...
    1    neu      ---  ....
    2    neu      ---  ....
    3    neu      ---  ....

    Diese Tabelle hat drei frische Einträge, die von Clients bearbeitet werden sollen. Dein bisheriger Ansatz dürfte gewesen sein, dass du zunächst mit SELECT nachschaust, ob Einträge zur Verfügung stehen, und den jeweiligen Eintrag dann mit UPDATE lockst, damit kein anderer mehr rankommt. Das führt bekanntermaßen zu Problemen. :)

    Wenn du stattdessen folgendes UPDATE auf obige Tabelle machst, dann kriegst du exakt _einen_ Datensatz verändert und kannst ihn _hinterher_ mit SELECT auslesen:
    UPDATE tabelle SET status="lock", CID="23" WHERE status="neu" LIMIT 1

    LIMIT 1 sorgt dafür, dass exakt ein Datensatz verändert wird, und nicht alle. WHERE status="neu" schließt alle Zeilen aus, die nicht neu sind (wie du siehst, sind das zumindest schon mal nicht die Zeilen, die durch diese Operation auf "locked" gestellt wurden - doch dazu gleich mehr).

    Nach dieser Operation hast du genau eine Zeile in der Datenbank, die "locked" ist und als CID die jeweilige Client-ID hat. Danach kannst du SELECTieren:
    SELECT ... FROM tabelle WHERE status="lock" AND CID="23".

    Diesen Eintrag verarbeitest du dann - und wenn du fertig bist, gibst du ihn mit
    UPDATE tabelle SET status="frei", CID="---" WHERE id="..."
    wieder frei. Beachte den dritten Statuszustand "frei" - nur damit kannst du brandneue Einträge von bereits bearbeiteten Einträgen unterscheiden - falls ein alter Eintrag bearbeitet werden soll, kannst du den Status ja wieder auf "locked" setzen.

    Wenn die Gefahr besteht, dass dein Datenbankdesign durch Systemabstürze etc. durcheinanderkommt, d.h. wenn die Möglichkeit besteht, dass ein gelockter Eintrag nicht mit 100% Sicherheit am Ende der Bearbeitung auf "frei" gesetzt werden kann, dann mußt du, damit du einen Eintrag beim SELECT zweifelsfrei wiederkriegst, mit eindeutigen IDs arbeiten, die du beim UPDATE mit einfügst:

    UPDATE tabelle SET status="lock", CID="23", UID="uniqueID" WHERE status="neu" LIMIT 1

    Die Spalte UID muß natürlich hinzugefügt werden.

    Da du dir die uniqueID vor dem Update ausdenkst (PHP bietet z.B. eine entsprechde Funktion) und merkst, kannst du damit das SELECT eindeutig machen:
    SELECT ... FROM tabelle WHERE status="lock" AND CID="23" AND UID="uniqueID"

    Du kannst feststellen, ob was im System schiefgegangen ist (d.h. gelockte Einträge nicht wieder freigegeben wurden), indem du für jede CID ein SELECT für gelockte Einträge ausführst. Das Ergebnis darf maximal aus _einer_ Zeile bestehen (nur ein Lock pro Client zum Bearbeiten pro Zeit) - andernfalls mußt du irgendwie aufräumen. Dieses Problem wirst du unter Umständen aber auch mit Transaktionen haben.

    - Sven Rautenberg

    --
    Diese Signatur gilt nur am Freitag.
    1. Moin!

      UPDATE tabelle SET status="lock", CID="23" WHERE status="neu" LIMIT 1

      Anzumerken wäre, dass MySQL das LIMIT ab Version 3.23 unterstützt - das dürfte hinreichend sein, da diese Version die älteste ist, die auf mysql.com zum Download bereitsteht und immerhin schon bis Version 3.23.53 gekommen ist - sie dürfte also so ziemlich überall anzutreffen sein.

      - Sven Rautenberg

      --
      Diese Signatur gilt nur am Freitag.
    2. Danke für deine Hilfe!

      genau so bzw. so ähnlich habe ich es nun auch gemacht. Allerdings schon vor deinem Posting. Trotzdem viel Dank!

      Allerdings müßte ich MySQL auf die 4.x Beta updaten, da ich sonst im UPDATE Befehl kein ORDER BY hätte nutzen können.

      Disaster

      1. Hi!

        genau so bzw. so ähnlich habe ich es nun auch gemacht. Allerdings schon vor deinem Posting. Trotzdem viel Dank!

        Allerdings müßte ich MySQL auf die 4.x Beta updaten, da ich sonst im UPDATE Befehl kein ORDER BY hätte nutzen können.

        Wozu das?

        Grüße
        Andreas

  5. Hi,

    hab' nicht den ganzen Thread gelesen aber:

    update
     table_a
    set
     datafiled_a = (select datafield_b from table_b where...),

    geht doch, wenn die select-abfrage genau einen Datensatz/Datenfeld zurückliefert.

    Gruss,
    Lude