使用MySQL的LAST_INSERT_ID(转)

时间:2022-09-21 22:48:03

The ID that was generated is maintained in the server on a per-connection basis.

LAST_INSERT_ID是基于单个connection的, 不可能被其它的客户端连接改变。

可以用 SELECT LAST_INSERT_ID(); 查询LAST_INSERT_ID的值.

Important: If you insert multiple rows using a single INSERT statement, LAST_INSERT_ID() returns the value generated for the first inserted row only.

使用单INSERT语句插入多条记录, LAST_INSERT_ID只返回插入的第一条记录产生的值. 比如
mysql> INSERT INTO t VALUES (NULL, 'aaaa'), (NULL, 'bbbb'), (NULL, 'cccc');  
mysql> SELECT * FROM t;  
+----+------+  
| id | name |  
+----+------+  
|   1 | Bob   |  
|   2 | aaaa |  
|   3 | bbbb |  
|   4 | cccc |  
+----+------+  
mysql> SELECT LAST_INSERT_ID();  
+------------------+  
| LAST_INSERT_ID() |  
+------------------+  
|                 2 |  
+------------------+ 

ID 2 是在插入第一条记录aaaa 时产生的.

LAST_INSERT_ID 是与table无关的,如果向表a插入数据后,再向表b插入数据,LAST_INSERT_ID会改变。

一般情况下获取刚插入的数据的id,使用select max(id) from table 是可以的。

但在多线程情况下,就不行了。在多用户交替插入数据的情况下max(id)显然不能用。

这就该使用LAST_INSERT_ID了,因为LAST_INSERT_ID是基于Connection的,只要每个线程都使用独立的Connection对象,LAST_INSERT_ID函数将返回该Connection对AUTO_INCREMENT列最新的insert or update操作生成的第一个record的ID。这个值不能被其它客户端(Connection)影响,保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁。

 

 

 

 

 

 

 

mysql的last_insert_id()是不是可靠的

 mysql的last_insert_id()不可靠 Mysql的API有个很有意义的函数last_insert_id()。这个函数的作用是,针对auto_increment字段,返回给定的 数据库链接,
上一步 INSERT 查询中产生的 AUTO_INCREMENT 的 ID 号。如果没有指定数据库链接,则使用上一个打开的连接。
 
很多人质疑last_insert_id()是否是可靠的,以前我也犹豫过。
 
事实上的结果是mysql_insert_id决不会取错。首先做个测试,
在mysql_query("insert.....);之后立刻sleep(1100),其间再做些其他的insert.

然后发现在mysql_insert_id取的值都不会和其他的冲突。
 
看了半天mysql的代码。mysql_insert_id是这么定义的
my_ulonglong STDCALL mysql_insert_id(MYSQL *mysql)
{
  return mysql->;last_used_con->;insert_id;
}

 
MYSQL是个结构体,里面包括数据库链接和一些当前数据库链接的状态值,
其中在MYSQL结构体里面有insert_id,mysql_insert_id函数返回的就是结构体里面的这个值。

 
typedef struct st_mysql
{
  NET net;
  gptr connector_fd;
  char *host,*user,*passwd,*unix_socket,*server_version,*host_info,*info;
  char *db;
  struct charset_info_st *charset;
  MYSQL_FIELD *fields;
  MEM_ROOT field_alloc;
  my_ulonglong affected_rows;
  my_ulonglong insert_id;
  my_ulonglong extra_info;
  unsigned long thread_id;
  unsigned long packet_length;
  unsigned int port;
  unsigned long client_flag,server_capabilities;
  unsigned int protocol_version;
  unsigned int field_count;
  unsigned int server_status;
  unsigned int server_language;
  unsigned int warning_count;
  struct st_mysql_options options;
  enum mysql_status status;
  my_bool free_me;
  my_bool reconnect;
 
 
  char scramble[SCRAMBLE_LENGTH+1];
 

  my_bool rpl_pivot;
 
  struct st_mysql* master, *next_slave;
  struct st_mysql* last_used_slave;

  struct st_mysql* last_used_con;
  LIST *stmts;
  const struct st_mysql_methods *methods;
  void *thd;
 
  my_bool *unbuffered_fetch_owner;
} MYSQL;

把insert_id理解成max(id)是错误的,因为有并发存在。
结构体里面有insert_id是针对当前MYSQL连接的,而每次mysql_query操作在mysql服务器上可以理解为一次“原子”操作。