|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
Hi everyone, One of the problems I'm having with the upcoming MySql support is the lack of @@IDENTITY. I'm now trying to come up with a solution that works for Sql Server, MySql, and others without the use of @@IDENTITY. Original: * ID = SqlHelper.Execute("INSERT INTO X(a,b,c) VALUES(A,B,C); SELECT @@IDENTITY") Proposed solution: * lock(SqlHelper) * ID = SqlHelper.Execute("SELECT MAX(id)+1 FROM X") * if(ID==null) ID=1 * SqlHelper.Execute("INSERT INTO X(id,a,b,c) VALUES(ID,A,B,C)") * unlock(SqlHelper) (This is of course pseudocode, for SQL Server I'd need SET IDENTITY_INSERT.) Do you think the following solution is equivalent to the original?Do you know something better?Equivalent should mean here, not necessarily generating the same ID's, but maintaining functionality and consistence all over the database. Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
following => preceding of course... happens when you cut-paste late in the evening. Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
Rank: Enthusiast
Joined: 12/22/2007 Posts: 12
|
Hi Ruben, MySQL has a AUTO_INCREMENT attribute which is equal to what you are trying to archive, I guess. More here: http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
Yes that's true, and the AUTO_INCREMENT attribute is exactly what I used for the table declaration. Further, there's the mysql_insert_id() function which then could replace @@IDENTITY, but it doesn't seem to work the same way. (Or does it?) Someone gave me a slightly better idea: "Let's have the logic backwards. You want to perform the insert first, and THEN get the MAX(id) which will provide the ID of the just inserted row." Might be a little less tricky. Or is there any better? Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
"slightly better" means "slightly better than the original idea" of course, I appreciate you help me thinking! ;) Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
 Rank: Fanatic
Joined: 11/24/2006 Posts: 321 Location: Stockholm, Sweden
|
There is also a parameter called LAST_INSERT_ID() that seems to be the same thing as @@IDENTITY. Quote:When a new AUTO_INCREMENT value has been generated, you can also obtain it by executing a SELECT LAST_INSERT_ID() statement with mysql_query() and retrieving the value from the result set returned by the statement. For LAST_INSERT_ID(), the most recently generated ID is maintained in the server on a per-connection basis. It is not changed by another client. It is not even changed if you update another AUTO_INCREMENT column with a non-magic value (that is, a value that is not NULL and not 0). Using LAST_INSERT_ID() and AUTO_INCREMENT columns simultaneously from multiple clients is perfectly valid. Each client will receive the last inserted ID for the last statement that client executed. Source: http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html /Thomas
Web Developer at Kärnhuset - http://www.karnhuset.net - Stockholm, Sweden
|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
Thanks for looking this up. Would there be any difference between this expressions, provided the same query was executed? LAST_INSERT_ID() - @@IDENTITY - MAX(id) Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
 Rank: Fanatic
Joined: 11/24/2006 Posts: 321 Location: Stockholm, Sweden
|
Yes, I believe there could (in theory) be differences. I have never worked in MySQL, but this definition of LAST_INSERT_ID() caugth my attention: For LAST_INSERT_ID(), the most recently generated ID is maintained in the server on a per-connection basis. It is not changed by another client.and: Using LAST_INSERT_ID() and AUTO_INCREMENT columns simultaneously from multiple clients is perfectly valid. Each client will receive the last inserted ID for the last statement that client executed.If I interpret this correctly, it is possible for another user (using another connection) to go in and add a new record and your execution of LAST_INSERT_ID() wouldn't return the ID of that user's recently added record but rather the ID of the last record that YOU (your connection) added to the database. Do you all agree? A SELECT MAX(ID) on the other hand would return the highest ID-number regardless of which connection is used to query the database. This means you should use LAST_INSERT_ID() if you want to get the ID of the record that you just inserted. If you want the ID of the record that anyone just inserted you should use SELECT MAX(ID). But I don't know if any of this really matters since you are only going to use the database together with the webserver (IIS) and I think that the webserver is considered a single user and using a single connection to the database(?)
Web Developer at Kärnhuset - http://www.karnhuset.net - Stockholm, Sweden
|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
Thanks! Thomas Kahn wrote: This means you should use LAST_INSERT_ID() if you want to get the ID of the record that you just inserted. If you want the ID of the record that anyone just inserted you should use SELECT MAX(ID).
The lock on the SqlHelper should make both equal, hopefully. Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
Rank: Devotee
Joined: 10/30/2007 Posts: 71 Location: Israel
|
Ruben Verborgh wrote:Thanks! Thomas Kahn wrote: This means you should use LAST_INSERT_ID() if you want to get the ID of the record that you just inserted. If you want the ID of the record that anyone just inserted you should use SELECT MAX(ID).
The lock on the SqlHelper should make both equal, hopefully. I wouldn't lock SqlHelper globally, at least not frequently. This is going to be an issue with crouded sites where DB updates will be made through the front end. I'm not familiar with the source enough to point at a specific issue, but from my experience with DBs this is not the best way to approach this. I think you should consider the approach for each case, preventing the lock as much as possible. So when you only need to find the ID of the record you inserted, just call LAST_INSERT_ID(). For other cases when you need the next ID value available use SELECT MAX(ID), but I don't see why this is needed since this field has AUTO_INCREMENT set? Itamar.
|
|
 Rank: Aficionado
Joined: 12/21/2007 Posts: 122 Location: Belgium
|
The ID has to be retrieved after the insert, to store in the local objects and possibly create new object referring to this ID. I've used a lock-solution anyway, but this shouldn't be a problem: the lock-section will only prevent other lock-sections from executing at the same time, all other instructions will be allowed to pass through. You can check out the code in the thread I started today. (Search for "lock (SqlHelper)", you'll come across 10 sections or so.) Umbraco Core Team Developer | Working on vNext | LinkedIn
|
|
|
Guest |