MySQL LAST_INSERT_ID Query - mysql

I've had a look at the official documentation but I'm still a bit confused.
Say I have a procedure and it runs and performs an insert and then I request LAST_INSERT_ID(), am I getting the last insert id from the insert just done by my instance of the procedure running or is it the last insert id on the table by any instance/session that's called the procedure?
For example say the last inserted record ID was 4 and I called the procedure and my insert would be id 5 but my insert fails will I get 4 being returned as the last insert id or a null/0 value?

That very link to the documentation page that you gave in the question has an answer:
The ID that was generated is maintained in the server on a
per-connection basis. This means that the value returned by the
function to a given client is the first AUTO_INCREMENT value generated
for most recent statement affecting an AUTO_INCREMENT column by that
client. This value cannot be affected by other clients, even if they
generate AUTO_INCREMENT values of their own. This behavior ensures
that each client can retrieve its own ID without concern for the
activity of other clients, and without the need for locks or
transactions.
So, there is no race condition from other clients. You need to request the LAST_INSERT_ID() in the same connection as INSERT to get correct result.
As for, what happens when transaction is rolled back, it is undefined:
If the previous statement returned an error, the value of
LAST_INSERT_ID() is undefined. For transactional tables, if the
statement is rolled back due to an error, the value of
LAST_INSERT_ID() is left undefined. For manual ROLLBACK, the value of
LAST_INSERT_ID() is not restored to that before the transaction; it
remains as it was at the point of the ROLLBACK.

The documentation you linked to says:
The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own.
This means you can safely rely on the value returned by LAST_INSERT_ID(). It is the most recent auto incremented value generated by the same instance of the code that calls LAST_INSERT_ID(). Of course, you have to call it right after the INSERT statement you want to get the value for, it cannot return the values generated by the second most recent INSERT statement or older.

Related

Is it possible to get LAST_INSERT_ID() from different database?

Suppose, that we have 2 databases: a and b, and tables a.test1 and b.test2.
If I need to insert a row into table a.test1, and return LAST_INSERT_ID() to insert into b.test2, will LAST_INSERT_ID() return value from another database? Is it reliable?
I didn't find anything in the manual, but ##IDENTITY depends on client session, so it should be portable between two databases. Isn't it?
LAST_INSERT_ID() always gives you the id of the row inserted by the last INSERT statement you executed on the current connection, irrespective of what table (and what database!) that row went into.
From Mysql documentation:The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.
Inshort Both *LAST_INSERT_ID()* and *mysql_insert_id()* work as advertised i.e.: they will retrieve the last id inserted into any table during the current session/connection.

LAST_INSERT_ID after restarting MySQL

I'm trying to retrieve the LAST_INSERT_ID by following statements after inserting a new record, it works fine.
SELECT LAST_INSERT_ID();
The problem
When Inserting a new record in table and restart MySQL Server and then trying to retrieve LAST_INSERT_ID, it gets 0 value!
LAST_INSERT_ID just works before restarting MySQL or rebooting system ?
Any help would be appreciated.
as stated in MySQL Docs,
The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.
Which means - after restart for your set of statements there is no statement affecting AUTO_INCREMENT value, so the value is undefined.
See this text in the LAST_INSERT_ID manual page:
The ID that was generated is maintained in the server on a per-connection basis.
If you restart the server, or disconnect and reconnect againg, then you are not using the same connection as when you did the insert, so that's why you get 0
As it was already stated based on MySQL Reference Manual: function_last-insert-id:
The ID that was generated is maintained in the server on a
per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client.
To get what you need, just make a new query:
SELECT MAX(ID) FROM ExampleTable;
in case you can't use LAST_INSERT_ID in the intended way.

AUTO_INCREMENT and LAST_INSERT_ID

I'm using AUTO_INCREMENT and I would like to get that ID of inserted row so that I could update another table using ID as common field between the 2 tables.
I understood that LAST_INSERT_ID will get last ID. However, my concern is that, the database is accessed at same time by many users. Hence, there might be another process accessed the table and also inserted a new row at same time.
Does LAST_INSERT_ID return just the last ID regardless of the connection used, or only return last ID for the connection that I'm using?
Notice, I'm accessing MySQL database using connection pool in Tomcat server.
In summary, I need to insert a row in table A with auto increment, than I need to insert row in table B, which need to be linked to table A using the AUTO_INCREMENT value.
SELECT max(employeeid) FROM Employee;
The above query returns the value of employeeid of last inserted record in Employee table because employeeid is an auto increment column. This seems to be OK, but suppose two threads are executing insert operation simultaneously, there is a chance that you get wrong id of last inserted record!
Don’t worry, MySQL provides a function which returns the value of auto increment column of last inserted record.
SELECT LAST_INSERT_ID();
LAST_INSERT_ID() is always connection specific, this means even if insert operation is carried out simultaneously from different connections, it always returns the value of current connection specific operation.
So you have to first insert record in Employee table, run the above query to get the id value and use this to insert in second table.
LAST_INSERT_ID() work in context, it should be in transactions or inside user defined stored procedures or user defined functions.
LAST_INSERT_ID is connection specific. That's true, but you should be careful if you use connection pooling. This may be problematic when you perform successive INSERT IGNORE statements in a loop and the pool gives you the same connection at each iteration.
For example; Assume that you receive the same (open) connection for each of the below:
INSERT IGNORE ... some-new-id >>> LAST_INSERT_ID returns 100
INSERT IGNORE ... some-existing-id >>> LAST_INSERT_ID still returns 100 (result of the previous operation)
It is always good to check whether the INSERT operation has in fact inserted any rows before calling LAST_INSERT_ID.
LAST_INSERT_ID return the last insert id for the current session.
As long as you don't insert more than one entry with your current connection, it is valid.
Further information here: https://dba.stackexchange.com/questions/21181/is-mysqls-last-insert-id-function-guaranteed-to-be-correct
(i would link to mysql.com, but it'S currently down for me)

MySQL Stored Procedures and Last Inserted Row

I'm curious whether this is a possibility. I have a stored procedure which Inserts and then retrieves the last insert id. What if 2 users both use the procedure at the same time, is something like this possible?
User 1
User 2
Insert 1
Insert 2
GetsLastid 2
GetsLastid 2
Could the 2 calls of the stored procedure interlace the sequence of the insert queries? Or will one take lead?
Thank you!
That's not a problem. From the fine manual:
The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own.
So the last_insert_id() value is always per-session (AKA connection) and you have two sessions in play, the can't interfere with each other's last_insert_id() values.
That said, it is a good idea to grab the last_insert_id() value and store it in a variable as soon after the INSERT as possible. If you do something else that does an INSERT behind your back — say you call another procedure that has logging added two months down the road and that logging does an INSERT — you will lose the last_insert_id() value that you want.

MySQL and PDO: Could PDO::lastInsertId theoretically fail?

I have been pondering on this for a while.
Consider a web application of huge proportions, where, let's say, millions of SQL queries are performed every second.
I run my code:
$q = $db->prepare('INSERT INTO Table
(First,Second,Third,Fourth)
VALUES (?,?,?,?)');
$q->execute(array($first,$second,$third,$fourth));
Then immediately after, I want to fetch the auto incremented ID of this last query:
$id = $db->lastInsertId();
Is it possible for lastInsertId to fail, i.e. fetch the ID of some SQL insert query that was executed between my two code blocks?
Secondary:
If it can fail, what would be the best way to plug this possible leak?
Would it be safer to create another SQL query to fetch the proper ID from the database, just to be sure?
It will always be safe provided that the PDO implementation is not doing something really bone-headed. The following is from the MySQL information on last_insert_id:
The ID that was generated is maintained in the server on a per-connection basis. This means that the value returned by the function to a given client is the first AUTO_INCREMENT value generated for most recent statement affecting an AUTO_INCREMENT column by that client. This value cannot be affected by other clients, even if they generate AUTO_INCREMENT values of their own. This behavior ensures that each client can retrieve its own ID without concern for the activity of other clients, and without the need for locks or transactions.
No. lastInsertId is per-connection, and doesn't require a request to the server - mysql always sends it back in its response packet.
So if the execute method doesn't throw an exception, then you are guaranteed to have the right value in lastInsertId.
It won't ever give you the insert ID of anything else, unless your query failed for some reason (e.g. invalid syntax) in which case it might give you the insert ID from the previous one on the same connection. But not anybody else's.