Mehrere zeitgleiche Querys bearbeiten die gleiche Zelle

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Mehrere zeitgleiche Querys bearbeiten die gleiche Zelle

    Hallo,

    ich habe eine Verständnisfrage zu mySQL Tabellenabfragen.

    Ich habe eine Tabelle "Rating" mit den Spalten id und rating

    Rating
    Code:
    +----+-------+
    |id  |rating |
    +----+-------+
    |1   |100    |
    +----+-------+
    |2   |150    |
    +----+-------+

    Der User kann auf der Internetseite das Rating jeweils um einen Punkt erhöhen oder erniedrigen.
    Auf der seite update.php?id=1 mach ich dann folgendes:
    - aktuelles rating der id auslesen
    - rating um 1 erhöhen
    - neues rating in die Tabelle schreiben

    Was passiert wenn mehrere User (fast) zur gleichen Zeit die gleiche Zelle bearbeiten?
    Dann könnte ja das folgende passieren oder?

    Code:
       User1                   User2
         |                       |  
         |                       |
    rating auslesen              |
    rating = 100                 |
         |                       |
         |                   rating auslesen
         |                   rating = 100
         |                       |
    rating um 1 erhöhen          |
    rating = 101                 |
         |                       |
         |                 rating um 1 erhöhen
         |                  rating = 101
         |                       |
    rating in Tabelle            |      
    schreiben                    |
    rating = 101                 |
                       rating in Tabelle schreiben
                             rating = 101


    In dem fall wäre ja das Rating 101 obwohl es 102 sein sollte. Oder kann soetwas nicht passieren?


    Ansonsten könnte ich ja noch eine Tabelle "Buffer" erstellen in der ich einfach jede Bewertung erfasse und diese dann in einem separaten Skript abarbeite.



    Hoffe ihr versteht was ich sagen will

    Danke schonmal

  • #2
    Wenn du zuerst den aktuellen Wert ausliest, und dann anschließend den entsprechend erhöhten Wert schreibst, dann hast du ein sog. TOCTTOU-Problem – und um das zu verhindern, müsstest du beides in eine Transaktion kapseln.

    Aber du brauchst hier gar kein SELECT vor dem UPDATE – du kannst gleich im UPDATE schreiben, SET spalte = spalte + 1 (oder eben - 1).

    Allerdings hat deine Methode, jeweils nur die Summe der Votings zu speichern, doch einige Nachteile – du kannst nicht verhindern, dass ein Nutzer mehrfach voted, du kannst dem Nutzer sein eigenen Votings aus der Vergangenheit nicht mehr anzeigen, du kannst keine statistischen Auswertungen machen wie bspw. ein Durchschnittsvote errechnen, etc.

    Deshalb wäre es schon angebrachter, einzelne Datensätze bestehend aus Nutzer-ID, Artikel-ID (oder was auch immer du bewerten lässt), und dem jeweiligen einzelnen Vote zu speichern. Die Berechnungen (Summe, Durchschnitt, etc.) machst du dann mit MySQLs Aggregat-Funktionen.
    I don't believe in rebirth. Actually, I never did in my whole lives.

    Kommentar


    • #3
      Danke für deine Antwort.

      Das mit dem Rating um 1 erhöhen war nur ein einfaches Beispiel. Ich will eigentlich sowas wie ein Elo-Rating implementieren info.

      Wenn ich ne einfache Rechenoperation hab wie +1 dann kann ich da ja leicht in ein UPDATE schreiben. Was aber wenn ich kompliziertere Rechenoperationen ausführen muss, die ich nicht in ein UPDATE reinpacken kann?

      Soll ich dann einfach eine separate Tabelle anlegen die alle "Ratings" sammelt und diese nach jedem Tag in einem Skript abarbeiten, welches die Haupttabelle mit den Ratings aktualisiert? So hätte ich ja das TOCTTOU-Problem nicht mehr, da nur ein Skript in meine Haupttabelle schreibt.

      Oder gibt es eine andere Lösung?

      Gruß

      Kommentar


      • #4
        Oder gibt es eine andere Lösung?
        MySQL :: MySQL 5.1 Referenzhandbuch :: 1.9.5.3 Transaktionen
        Oder auch: MySQL :: MySQL 5.1 Referenzhandbuch :: 13.4.5 LOCK TABLES und UNLOCK TABLES
        Wir werden alle sterben

        Kommentar


        • #5
          hmm aber wenn ich eine Tabelle sperre kann ja solange kein anderer drauf zugreifen. Bei vielen Benutzern wäre das ja nicht ideal.

          Welche Lösung würdest du empfehlen?

          Kommentar


          • #6
            Wenn du Race Conditions verhindern willst/musst, dann musst du das auch tun.

            Was ist schlimmer?
            a: Fehler durch Race Conditions
            b: Der User muss ein paar Zehntel Sekunden warten
            ???



            Welche Lösung würdest du empfehlen?
            Sachte ich doch schon....
            Locks oder Transaktionen.
            Alleine, weil es keine Alternativen gibt.

            Und Transaktionen, weil es die Gefahr von Deadlocks mildert.
            Wir werden alle sterben

            Kommentar


            • #7
              im übrigen widersprichst du dir selbst

              Ein Voting-System kann durchaus race-Conditions deiner Art haben

              Ein ELO-Punkte System kann NICHT : ein Schachspieler spielt EIN Spiel - daraus ergibt sich EIN Ergebnis - und durch den Vergleich mit der ELO-Punktzahl des Gegners dann eine kleine Änderung der beiden ELO-Punktzahlen ... ergo führt 1 Spiel zu exakt 2 Updates in der ELO-Tabelle ... und damit gibt es auch keine Race-Condition, weil der Spieler nunmal nicht 2 Spiele gleichzeitig macht - es dauert wenigstens ein paar Minuten (Blitzschach - wobei Blitzschach nichtmal auf die ELO angewendet wird, sondern eher als Spaß-Turnier ) bis das nächste Ergebnis für die beteiligten Spieler hereinkommt - im Regelfall sogar Stunden...
              [font=Verdana]
              Wer LESEN kann, ist klar im Vorteil!
              [/font]

              Kommentar

              Lädt...
              X