Sandrine: Insert Fehler vermeiden durch Transaktionen?

Beitrag lesen

  1. Speicherung von Kundenname, Kundennummer etc. in Tabelle "kunde", Rückgabe neue "kundenid"
  2. Speicherung von Vertragsdaten wie Vertragsnr. Datum, Beschreibung in Tabelle "vertrag", Rückgabe neue "vertragid".
  3. Speicherung von  "kundenid" und "vertragid" in Relationstabelle "kunde_vertrag_rel"

Sofern demselben Vertrag nicht mehrere Kunden zugeordnet werden können, ist der dritte Schritt bzw. die Tabelle kunde_vertrag_rel sinnlos; platziere die Kunden-ID im Vertragsdatensatz.

Ich hatte in einem internen Test einen Fall, wo Step 1 und 2 gemacht wurde, aber die Relationstabelle Eintrag fehlte bzw. ich die "vertragid" nicht finden konnte.

Könnte man obiges Szenario mit einer Transaktion absichern?

Die Frage wäre erstmal, warum der banale Eintrag in der Relationstabelle fehlschlug.
Gründe lägen dafür nur im Bereich Platzmangel auf dem Datenspeicher, Verbindungsabbruch zur Datenbank, unerwarteter Abbruch des Skriptes selbst und andere derartige Katastrophenfälle.
Es ist sicher nicht so, dass eine Transaktion als Absicherung gegen unvollständig geschriebene Daten überflüssig wäre, ganz im Gegenteil, aber diese Gründe sind alle so außergewöhnlicher Natur, dass mir da eher noch etwas Größeres zu dräuen scheint, dem unbedingt auf den Grund gegangen werden muss.

Was mir nicht ganz klar ist: Bei der Speicherung der Daten macht das PHP-Script vorher diverse Prüfungen, ob z.b. der Kundenname schon da ist oder nicht.

Ein verkürztes Beispiel

..
$check_kunde = get_KundenDaten();

if(....){//Wenn kunde noch nicht vorhanden
$neueKundeid = InsertKundenData($Customername,$Customernumber..//Insert Kunden Daten in "kunde" Tabelle
}
..
$newvertragyid = InsertVertrag($_POST['vertragnr'].....//insert in "vertrag" Tabelle

if( (!empty($neueKundeid)) AND (!empty($newvertragyid)) ){//
...
InsertRelCustomerOppnr($neueKundeid,$newvertragyid );//Eintrag Relations Tabelle

if( (empty($neueKundeid)) AND (!empty($newvertragyid)) ){//wenn unter gleichem Kunde Name ein neuer Vertrag eingegeben wird
$neueKundeid= get_KundenID(.....);//vorhandene Kundenid holen
InsertRelCustomerOppnr($neueKundeid,$newvertragyid );//Eintrag Relations Tabelle

  

> Wie kann man obige Logik mit einer Transaktion verbinden?  
  
Dein Ablauf ist so schon etwas verquer: Du prüfst, ob ein Kunde schon bekannt ist und legst, falls nicht, einen neuen an. Danach legst du den Vertrag an. Anschließend drehst du dich zweimal im Kreis, indem du prüfst, ob du einen neuen Kunden angelegt hast: Falls ja, wird die Relation angelegt, falls nein, wird zum \_zweiten Mal\_ der bestehende Kunde abgefragt und dann legt ein separater, aber vollkommen identischer Aufruf die Relation an.  
  
Es ist, jedenfalls nach deinem Codeschnippsel, überflüssig, die Relation anzulegen in der Abhängigkeit davon, ob zuvor ein neuer Kunde angelegt wurde oder nicht. Die Relation wird angelegt, fertig. Du musst auch nicht zweimal innerhalb von Mikrosekunden denselben bestehenden Kunden abfragen.  
Last but not least scheint dein Code auch irgendwie nicht so recht auf den Fall einzugehen, dass das Anlegen des Vertrages fehlschlägt. Du fragst nämlich zweimal in Zusammenhang mit der Kunden-ID das Bestehen des Vertrages ab, obwohl das überflüssig wäre, wenn du gleich nach Vertragsanlage diesen Fehler abgefangen hättest (dann kämest du gar nicht mehr bei der Relation an).  
  
Geradlinig wäre dieser Weg:  
  
1\. Bestehende Kundendaten suchen und, so möglich, in kundenid ablegen.  
2\. Falls keine vorhanden, neuen Kunden anlegen und in kundenid ablegen.  
3\. Neuen Vertrag anlegen.  
4\. Relation anlegen.  
  
Die Transaktion sollte Punkt 3 und 4 umschließen, da die Kundenexistenz nicht abhängig vom Vertrag und der Relation ist. Nur die Relation ist abhängig vom Vertrag.  
Hast du die Kunden-ID im Vertrag mit der Kundendatenbank verbunden (Stichwort foreign key), fängt die Transaktion auch den Fall ab, dass zwischen Schritt 2 und 3 der Kunde flötengeht, aus welchem Grund auch immer (Atomkrieg, Weltuntergang, schwarzes Loch im Rechenzentrum, …).  
  

> In einer Transaktion selbst kann man ja nur SQL Befehle absetzen oder?  
  
Ja, aber falls die Ursache für den nicht ausgeführten dritten Schritt datenbankseitig liegt, wird der Fehler von der Transaktion aufgefangen. Aber wie ich oben schon schrieb, solltest du erstmal ergründen, warum Schritt 3 fehlschlägt, und dir anschließend überlegen, wozu du die Relationstabelle brauchst.