| 

.NET C# Java Javascript Exception

3
wie kann verhindert werden, dass ein doppelter DB-Eintrag erfolgt, wenn der User die Seite
aktualisiert (Refresh-Button)?
News:
02.12.2011
knopf009 39 4
5 Antworten
2
Deine Frage ist wenig konkret. Ich vermute, es handelt sich um eine Browser basierte Anwendung. Die verwendete Technologie spielt keine Rolle. Die Daten werden an einen Server geschickt, evt. über einen WebService??? Der Server stellt eine Schnittstelle zur Verfügung wie z.B. ServiceXY.Insert(myEntity). Damit ist klar, dass ein Datensatz eingefügt werden soll. Dieser Datensatz hat bestimmt eine ID (GUID). Nun schaust du in der Datenbank nach, ob es diese ID bereits gibt. Wenn ja, dann darf der Datensatz nicht eingefügt werden und eine entsprechende Meldung geht zurück an den Client.
Mit dieser Vorgehensweise ist es auch egal, von was für einem Client der Datensatz kommt, da dieses Problem serverseitig behandelt wird.
02.12.2011
Jürgen Luhr 7,1k 2 9
3
Kennt hier wirklich niemand das PRG-Pattern? Das läuft kurz gesagt so:

  • Formular wird gePostet.
  • Der Server verarbeitet den Post, schickt als Antwort aber keine neue Seite, sondern einen HTTP-Redirect mit der URL der Antwortseite.
  • Der Browser holt sich die neue Seite per GET-Request.

Damit stehen in der Browser-Historie nur lesende GET-Requests, und der Nutzer kann so oft Refreshen und den Back-Button drücken, wie er will, er wird niemals mit der Frage konfrontiert werden, ob er die Formular-Daten nochmals absenden will.

Gute Webapplikations-Frameworks, in der Java-Welt zum Beispiel Tapestry, machen das von Haus aus so.

Damit will ich nicht sagen, dass der Ansatz von Jürgen damit überflüssig würde. In Remote-Szenarien sollten immer idempotente Operationen verwendet werden, und Jürgens Vorschlag läuft darauf hinaus, die den Post verarbeitende Operation idempotent zu machen. Streng genommen ist das PRG-Pattern also ein Mittel für mehr Usability - aber wie ich finde, ein sehr wichtiges. Als Nutzer weiß ich ja nicht, ob der Server-Programmierer seine Hausaufgaben gemacht hat und breche bei einer Nachfrage des Browsers wegen erneutem Senden der Formulardaten vorsichtshalber ab, mit der sehr ärgerlichen Konsequenz, dass ich dann irgendwo hängenbleibe.

In unkritischen Szenarien (Buchhaltung, wie Du sie erwähnst, fällt da wohl eher nicht mehr darunter; eher ein einfaches Forum oder so was) würde ich mich sogar rein auf PRG verlassen und Idempotenz am Server nur noch da anstreben, wo sie keinen nennenswerten Zusatzaufwand verursacht.

Update:
Da Du nach einem PHP-Beispiel gefragt hast: ich bin selbst kein PHP-Programmierer, aber dieses Beispiel macht auf mich einen ganz ordentlichen Eindruck. Prinzipiell hast Du wohl zwei Optionen: entweder machst Du alles wie bisher in einer PHP-Datei und baust eine Fallunterscheidung ein, ob der Request per POST oder GET kam (das ist der Ansatz des verlinkten Beispiels). Oder Du teilst Deinen Code auf zwei Dateien auf. Die eine wird in der Action des Formulars angegeben, schreibt in die DB und macht den Redirect auf die zweite, die sich dann nur noch um das Rendering kümmern muss.
03.12.2011
Matthias Hlawatsch 13,2k 4 9
1
zunächst einmal vielen Dank für die ausführliche und kompetente Antwort. Sinngemäß habe ich es verstanden. An der Umsetzung (Code) werde ich noch zu knabbern haben, da ich eher noch ein "Frischling" bin.
Aber das Problem an sich scheinen auch größere Firmen zu haben. Bei Reichelt z.B. habe ich insg. 6 Kataloge erhalten, weil ich die Seite mehrfach neu geladen habe und das anscheinend nicht verhindert wurde.

Denn eine Meldung an sich (das nach dem refresh ein weiterer DB-Eintrag gemacht wurde) kommt ja nicht automatisch.

Also werde ich zusehen, das HTTP-Redirect mit der ID anzuweden.
knopf009 03.12.2011
...wie würde das denn in PHP aussehen (Code)?
knopf009 03.12.2011
siehe das Update meiner Antwort
Matthias Hlawatsch 05.12.2011
...das funktioniert. Nochmals vielen Dank!
knopf009 07.12.2011
0
ok, sorry. Mit der Antwort bin ich falsch gelandet, aber ich poste selten in ein Forum.
Den Button per JS sperren ist zwar auch ne Lösung, aber bei mir handelt es sich eher um "versehentliche" Doppeleinträge per "Refresh". Also werde ich wohl so etwas mit einer ID einbauen und diese vor dem Eintrag abfragen. Ich habe eigentlich deshalb hier nachgefragt, weil es vielleicht mittlerweile eine andere Möglichkeit gibt, dieses "Refresh" zu verhindern. Aber das ist noch nicht der Fall...vielen DANK für eure Mithilfe!
02.12.2011
knopf009 39 4
1
Du könntest auch ein ein Uniq-Index auf das ID, E-Mail oder welches auch immer Feld legen. Und würdest direkt von der DB einen Error bekommen, sollte dieser erneut eingefügt werden.
LiRo 02.12.2011
das hört sich interessant an. Vielleicht hier doch ein paar mehr Info's zu meinem Projekt: es handelt sich um eine Buchhaltungs-Datenbank. Wenn der User auf "buchen" klickt, wird der Eintrag vorgenommen. Jetzt kommt es aber vor, dass (aus welchen Gründen auch immer", der User einen "Refresh" durchführt. Dann wird dieser Eintrag, solange $_POST vorhanden ist, widerholt. Und das muß ich natürlich verhindern. Oft lese ich die Variante mit der "ID", was mir auch einleuchtet. Aber ich bin ja offen für alles neue... :-)
knopf009 02.12.2011
Dann kannst du doch das machen, was Nicolai geschrieben hat, den User einfach wegleiten. Also den Eintrag speichern und direkt danach eine Umleitung auf z.B. den gespeicherten Eintrag oder der Liste der Einträge machen.
LiRo 02.12.2011
ich kann den User nicht einfach wegleiten. Denn wenn es sich um einen "nicht bösen" User handelt, macht er den Refresh ja nicht absichtlich. Also insofern nutzt auch das sperren des Buttons nichts. Der User zahlt ja für die Benutzung der DB. Die Lösung von Jürgen Luhr scheint die beste zu sein... nochmals vielen Dank für die "Anteilnahme"
knopf009 02.12.2011
Wieso kannst du das nicht? Und um welche Art von Software geht es dabei überhaupt?
LiRo 02.12.2011
0
Noch ein anderer Ansatz: wenn es für Dich ok ist, dass Deine Seite nur noch mit aktiviertem Javascript funktioniert, könntest Du auch die Daten per Ajax-Request zum Server schicken. Danach manipulierst Du per Javascript die Seite wie gewünscht - einfache "Dankeschön"-Anzeige oder Aktualisierung der angezeigten Daten. Ein Refresh wird dann nur das (rein lesende) Neuladen der Seite verursachen mit dem gleichen HTTP-Request, mit dem der Nutzer vor dem Abschicken der Daten auf die Seite gekommen ist.
03.12.2011
Matthias Hlawatsch 13,2k 4 9
-1
ja, anscheinend geht es nicht anders. Merci!
02.12.2011
knopf009 39 4
Kommentare -bitte- auch als Kommentar schreiben.
LiRo 02.12.2011
2
Da stimme ich Liro zu. Zum Thema: Was man machen kann ist zum Beispiel den Button per JavaScript sperren. Dann verhindert man zumindest dass das Formular versehentlich 2 mal abgeschickt wird. Ansonsten den Benutzer von der "Speichern" Seite wegleiten.
Nicolai Schönberg 02.12.2011
1
Schreib das doch als Antwort ;)
LiRo 02.12.2011
@Nicolai: Da hat LiRo recht. Das ist auch eine Antwort wert.
Meine Meinung dazu:
serverseitig -> notwendig
zusätzlich clientseitig -> benutzerfreundlich
Jürgen Luhr 02.12.2011

Stelle deine Datenbank-Frage jetzt!