johny7: MySQL: letzte autoincrement ID auslesen

Moin allerseits,

ich verwende in einem bestehenden Framework das Plugin ezSQL, um Datenbankoperationen in MySQL durch zu führen.

Wenn ich nun  mit INSERT einen Datensatz in eine Tabelle schreibe, möchte ich die ID des soeben geschriebenen Eintrags haben, um diesen Eintrag anschließend an zu zeigen. mysql_insert_id() hat irgendwie nicht funktioniert. Ich weiß bei ezSQL auch nicht, wie ich die Resource an mysql_insert_id() übergebe.
Momentan habe ich es folgendermaßen gelöst:

  
//	Anlegen eines neuen Datensatzes  
$dbfeedback->query("INSERT INTO ticket SET (datum=NOW(),user='".$user."',email='".check($_POST['email'])."');");  
//	ID des gerade angelegten Datensatzes auslesen  
$lastid = $dbfeedback->get_results("SELECT LAST_INSERT_ID();");  
foreach ($lastid[0] as $val)  
	{  
	$id = $val;  
	break 1;  
}  

Das komplizierte Konstrukt mit foreach habe ich , weil ich in $lastid ein Array bekomme, welches ein Objekt enthält, in welchem dann die Eigenschaft LAST_INSERT_ID() die ID hat. Diese Eigenschaft heißt aber LAST_INSERT_ID() und ich weiß nicht, wie ich mit Objektnotation darauf zugreifen soll. Wenn ich es mit $lastid[0]->LAST_INSERT_ID() versuche, denkt PHP, dass ich eine Methode aufrufe und gibt eine Fehlermeldung aus.

Mein eigentliche Frage ist: Was passiert, wenn zwischen dem Anlagen des Datensatzes und der Abfrage mit SELECT LAST_INSERT_ID() ein weiterer Datensatz (z.B. von einem anderen Client aus) angelegt worden ist? Wie kann ich garantieren, dass ich die ID des von mir gerade angelegten Datensatzes bekomme? Und wird das mit mysql_insert_id() automatisch garantiert?

Grüße, JN

--
ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
http://www.johny7.de
  1. Hallo johny7,

    Mein eigentliche Frage ist: Was passiert, wenn zwischen dem Anlagen des Datensatzes und der Abfrage mit SELECT LAST_INSERT_ID() ein weiterer Datensatz (z.B. von einem anderen Client aus) angelegt worden ist?

    Dann bekommst du dessen ID. Deshalb sollte man den Eintrag in die Tabelle und die Abfrage der ID atomar kapseln. Ähnliche Beispiele wären Update-Funktionen.

    Wie kann ich garantieren, dass ich die ID des von mir gerade angelegten Datensatzes bekomme? Und wird das mit mysql_insert_id() automatisch garantiert?

    Frage die ID sofort nach dem INSERT ab. Theoretisch gibt es da zwar immernoch eine Race-Condition, die ist aber zu vernachlässigen. Ansonsten beschäftige dich näher mit dem Thema -> http://www.google.de/#hl=de&q=race+condition+mysql.

    Grüße, Matze

    1. Moin!

      Mein eigentliche Frage ist: Was passiert, wenn zwischen dem Anlagen des Datensatzes und der Abfrage mit SELECT LAST_INSERT_ID() ein weiterer Datensatz (z.B. von einem anderen Client aus) angelegt worden ist?

      Dann bekommst du dessen ID. Deshalb sollte man den Eintrag in die Tabelle und die Abfrage der ID atomar kapseln. Ähnliche Beispiele wären Update-Funktionen.

      Nein, falsch!

      Die LAST_INSERT_ID() ist PRO CONNECTION immer die ID des letzten über diese Connection erzeugten Datensatzes. Wenn man also INSERT macht, und die Connection dann nicht trennt, und dann die Insert-ID abfragt, kriegt man garantiert die des eben gemachten Inserts. Das regelt die Datenbank so, alles andere hätte absolut keinen Sinn, denn Datenbanken bewegen sich schon immer in einem Multi-User-Umfeld.

      Wie kann ich garantieren, dass ich die ID des von mir gerade angelegten Datensatzes bekomme? Und wird das mit mysql_insert_id() automatisch garantiert?

      Frage die ID sofort nach dem INSERT ab. Theoretisch gibt es da zwar immernoch eine Race-Condition, die ist aber zu vernachlässigen. Ansonsten beschäftige dich näher mit dem Thema -> http://www.google.de/#hl=de&q=race+condition+mysql.

      Es gibt keinerlei Race-Condition. Du bist einfach falsch informiert - und das, obwohl die richtige Lösung zu dieser häufig gestellten Frage schon mehrfach hier im Forum geschrieben wurde...

      - Sven Rautenberg

      1. Hey Sven,

        Du bist einfach falsch informiert - und das, obwohl die richtige Lösung zu dieser häufig gestellten Frage schon mehrfach hier im Forum geschrieben wurde...

        und das obwohl ich meine Antwort auch nur aus dem Forum habe. Naja, man lernt halt nie aus.
        Wahrscheinlich spielen dann auch noch persistente Verbindungen eine Rolle.

        Danke für Korrektur!

        Grüße, Matze

        1. Hi!

          Wahrscheinlich spielen dann auch noch persistente Verbindungen eine Rolle.

          Nein, keine besondere. Der Wert ist pro Verbindung eindeutig. Ob diese permanent ist oder immer noch besteht, weil das Script sie oder sich noch nicht beendet hat, ist unerheblich.

          Lo!

      2. Moin allerseits,

        Die LAST_INSERT_ID() ist PRO CONNECTION immer die ID des letzten über diese Connection erzeugten Datensatzes. Wenn man also INSERT macht, und die Connection dann nicht trennt, und dann die Insert-ID abfragt, kriegt man garantiert die des eben gemachten Inserts. Das regelt die Datenbank so, alles andere hätte absolut keinen Sinn, denn Datenbanken bewegen sich schon immer in einem Multi-User-Umfeld.

        Das heißt für mich, es ist egal, ob ich über die PHP-Funktion oder über ein SELECT LAST_INSERT_ID() abfrage, ich bekomme das, was ich brauche?
        Welche Variante ist dann (warum) zu bevorzugen? Weiß auch jemand vielleicht, wie man das mit ezSQL handhabt bzw. wie ich nach der SQL-Abfrage ohne die Schleife auf die Eigenschaft des Objektes zugreifen kann?

        Grüße, JN

        --
        ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
        http://www.johny7.de
        1. Hi!

          Die LAST_INSERT_ID() ist PRO CONNECTION immer die ID des letzten über diese Connection erzeugten Datensatzes. [...]
          Das heißt für mich, es ist egal, ob ich über die PHP-Funktion oder über ein SELECT LAST_INSERT_ID() abfrage, ich bekomme das, was ich brauche?

          Solange es die selbe Verbindung ist.

          Welche Variante ist dann (warum) zu bevorzugen?

          Der Konsistenz wegen immer die des verwendeten Systems. Gemischt zwei Systeme zu verwenden, ist keine so gute Idee, weil/wenn du nicht weißt, wie das andere System intern arbeitet und welche Nebenwirkungen dein Eingriff hat.

          Weiß auch jemand vielleicht, wie man das mit ezSQL handhabt bzw. wie ich nach der SQL-Abfrage ohne die Schleife auf die Eigenschaft des Objektes zugreifen kann?

          Lies die Dokumentation. Es wird eine ez_sql_help.htm mitgeliefert, die die Antwort offenbart, wenn du im Browser (meist Strg+F) nach "insert" suchst.

          Desweiteren würdest du keine Schleife benötigen. Wenn feststeht, dass nur ein Datensatz zurückgeliefert wird, reicht genau eine-Fetch-Operation, oder wenn ezSQL dir bereits ein Array aller Datensätze liefert, der Zugriff auf das erste (und einzige) Element. Wenn du dann nicht weißt, was du geliefert bekommst, hilft eine Kontrollausgabe mit var_dump() oder print_r().

          Lo!

          1. Moin allerseits,

            Welche Variante ist dann (warum) zu bevorzugen?

            Der Konsistenz wegen immer die des verwendeten Systems. Gemischt zwei Systeme zu verwenden, ist keine so gute Idee, weil/wenn du nicht weißt, wie das andere System intern arbeitet und welche Nebenwirkungen dein Eingriff hat.

            Was heißt das jetzt? Ich verwende PHP und MySQL. Was ist jetzt zu bevorzugen?

            Lies die Dokumentation. Es wird eine ez_sql_help.htm mitgeliefert, die die Antwort offenbart, wenn du im Browser (meist Strg+F) nach "insert" suchst.

            Ach, sieh wie einfach...

            Des Weiteren würdest du keine Schleife benötigen. Wenn feststeht, dass nur ein Datensatz zurückgeliefert wird, reicht genau eine-Fetch-Operation, oder wenn ezSQL dir bereits ein Array aller Datensätze liefert, der Zugriff auf das erste (und einzige) Element. Wenn du dann nicht weißt, was du geliefert bekommst, hilft eine Kontrollausgabe mit var_dump() oder print_r().

            Richtig. Ich bekomme nach dem Aufruf mit ezSQL

              
            $lastid = $ez->get_results("SELECT LAST_INSERT_ID();");  
            var_dump();  
            
            

            folgende Ausgabe:

              
            array(1) {  
              [0]=>  
              object(stdClass)#7 (1) {  
                ["LAST_INSERT_ID()"]=>  
                string(1) "2"  
              }  
            }  
            
            

            Wie greife ich nun auf den String zu?

            Grüße, JN

            --
            ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)
            http://www.johny7.de
            1. Hi!

              Welche Variante ist dann (warum) zu bevorzugen?
              Der Konsistenz wegen immer die des verwendeten Systems. Gemischt zwei Systeme zu verwenden, ist keine so gute Idee, weil/wenn du nicht weißt, wie das andere System intern arbeitet und welche Nebenwirkungen dein Eingriff hat.
              Was heißt das jetzt? Ich verwende PHP und MySQL. Was ist jetzt zu bevorzugen?

              Du verwendest - aus welchem Grund auch immer - ezSQL als eine Abstraktionsschicht zum DBMS. Du solltest dann konsequent diese Abstraktionsschicht verwenden und nicht nebenher ein eigenes DBMS-Handling veranstalten.

              Richtig. Ich bekomme nach dem Aufruf mit ezSQL

              $lastid = $ez->get_results("SELECT LAST_INSERT_ID();");

              var_dump();

              
              > folgende Ausgabe:  
              > array(1) {  
              >   [0]=>  
              >   object(stdClass)#7 (1) {  
              >     ["LAST\_INSERT\_ID()"]=>  
              >     string(1) "2"  
              >   }  
              > }  
              > Wie greife ich nun auf den String zu?  
                
              Du kannst es dir mit einem Alias einfacher machen  
                
                SELECT LAST\_INSERT\_ID() foo  
                
              Dann reicht $lastid[0]->foo.  
                
              Eigenschaften, die wie deine "komische" Zeichen enthalten, sind etwas schwerer zu handhaben. Zunächst muss man wissen, dass man statt einer einfachen Zeichenkette, die den Eigenschaftennamen repräsentieren soll, auch einen komplexen zu berechnenden Ausdruck verwenden kann, den man in {}-Klammern setzen muss:  
                
                $objekt->{ausdruck}  
                
              Als Ausdruck kann man nun einen einfachen String  
                
                $lastid[0]->{'LAST\_INSERT\_ID()'}  
                
              oder auch was anderes berechnetes angeben:  
                
                $objekt->{42 + 23}  
                
                
              Lo!
              
              1. Moin allerseits,

                Du verwendest - aus welchem Grund auch immer - ezSQL als eine Abstraktionsschicht zum DBMS. Du solltest dann konsequent diese Abstraktionsschicht verwenden und nicht nebenher ein eigenes DBMS-Handling veranstalten.

                Jup, jetzt kenne ich ja $ezsql->insert_id; Das ^^ war vorher und ich wollte jetzt nur wissen, wie ich das in dem Fall lösen müsste. Kann ja sein, dass mich so ein Fall mit komplizierten Ausdrücken in Objekten wieder mal trifft...

                Richtig. Ich bekomme nach dem Aufruf mit ezSQL

                $lastid = $ez->get_results("SELECT LAST_INSERT_ID();");

                var_dump();

                
                > > folgende Ausgabe:  
                > > array(1) {  
                > >   [0]=>  
                > >   object(stdClass)#7 (1) {  
                > >     ["LAST\_INSERT\_ID()"]=>  
                > >     string(1) "2"  
                > >   }  
                > > }  
                > > Wie greife ich nun auf den String zu?  
                >   
                > Du kannst es dir mit einem Alias einfacher machen  
                >   
                >   SELECT LAST\_INSERT\_ID() foo  
                
                Cool. Muss das nicht SELECT LAST\_INSERT\_ID() AS foo heißen?  
                  
                
                >   
                > Dann reicht $lastid[0]->foo.  
                
                Logisch.  
                  
                  
                
                > Eigenschaften, die wie deine "komische" Zeichen enthalten, sind etwas schwerer zu handhaben. Zunächst muss man wissen, dass man statt einer einfachen Zeichenkette, die den Eigenschaftennamen repräsentieren soll, auch einen komplexen zu berechnenden Ausdruck verwenden kann, den man in {}-Klammern setzen muss:  
                  
                
                >   $objekt->{ausdruck}  
                >   
                > Als Ausdruck kann man nun einen einfachen String  
                >   
                >   $lastid[0]->{'LAST\_INSERT\_ID()'}  
                
                Genau danach habe ich gesucht. Danke.  
                  
                
                >   
                > oder auch was anderes berechnetes angeben:  
                >   
                >   $objekt->{42 + 23}  
                
                Das wäre adäquat zu $objekt->65 ?  
                  
                Grüße, JN
                
                -- 
                ie:{ fl:( br:^ va:| ls:[ fo:| rl:? n4:? ss:| de:] js:| ch:? sh:( mo:| zu:)  
                http://www.johny7.de
                
                1. Hi!

                  SELECT LAST_INSERT_ID() foo
                  Cool. Muss das nicht SELECT LAST_INSERT_ID() AS foo heißen?

                  Nein, das AS ist entbehrlich - sprich: optional.

                  $objekt->{42 + 23}
                  Das wäre adäquat zu $objekt->65 ?

                  Theoretisch ja, praktisch nicht, weil Bezeichner mit einem Buchstaben beginnen müssen, wenn man sie einfach so notieren will. $objekt->{65} wäre die richtige Notation.

                  Lo!