CREATE TABLE `t_a` (
  `a_id` int(11) NOT NULL AUTO_INCREMENT,
  `a_name` varchar(30) NOT NULL DEFAULT 'N/A',
  PRIMARY KEY (`a_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;CREATE TABLE `t_b` (
  `b_id` int(11) NOT NULL AUTO_INCREMENT,
  `b_name` varchar(30) NOT NULL DEFAULT 'N/A',
  `a_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`b_id`),
  KEY `a_id` (`a_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
create procedure sp_insert_b
(
p_aname varchar(30),
p_bname varchar(30)
)
begin
declare v_id int;
insert into t_a(a_name)values(p_aname);
select a_id into @v_id from t_a order by a limit 1;
set v_id=@v_id;
insert into t_b(b_name,a_id) values(p_bname,v_id);
end上面的存储过程执行时,会不会存在这样一种风险:有多个客户端同时调用存储过程,存储过程在执行select a_id into @v_id from t_a order by a limit 1;这句时,获取的id会不会错位?也就是说多个客户端调用同一个Server的同一个存储程序,存储程序是并行执行还是顺序执行?我理解的并行执行就是多个程序同时执行,顺序执行就是一个client端完了再执行另一个client端的,谢谢!

解决方案 »

  1.   

    MySQL 不保证你并发进程的访问顺序!
    如果你想取刚INSERT的a_id,最好用LAST_INSERT_ID()
    insert into t_a(a_name)values(p_aname);
    select LAST_INSERT_ID() into @v_id ;
      

  2.   

    LAST_INSERT_ID()是个function,我怎么知道这个LAST_INSERT_ID()是t_a的而不是t_b的呢?
    如何定位这个LAST_INSERT_ID()是基于哪张表的呢?
      

  3.   

    执行完insert t_a后立即取。
    最后一次INSERT是哪个表的,LAST_INSERT_ID()就是哪个表的。
      

  4.   

    如果Mysql不能保证并发进程的访问顺序,那么如何保证LAST_INSERT_ID()就是“我”刚调用程序插入的id,而不是“其他用户”在我插入之后,select之前插入的数据呢?
      

  5.   

    LAST_INSERT_ID() 是connection 级的,不同连接之间没有影响。
      

  6.   

    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. 为什么看一下帮助文档中的说明呢?
    MySQL官方文档 http://dev.mysql.com/doc/refman/5.1/zh/index.htmlLAST_INSERT_ID() LAST_INSERT_ID(expr) 
    自动返回最后一个INSERT或 UPDATE 问询为 AUTO_INCREMENT列设置的第一个 发生的值。mysql> SELECT LAST_INSERT_ID();        -> 195产生的ID 每次连接后保存在服务器中。这意味着函数向一个给定客户端返回的值是该客户端产生对影响AUTO_INCREMENT列的最新语句第一个 AUTO_INCREMENT值的。这个值不能被其它客户端影响,即使它们产生它们自己的 AUTO_INCREMENT值。这个行为保证了你能够找回自己的 ID 而不用担心其它客户端的活动,而且不需要加锁或处理。 假如你使用一个非“magic”值来更新某一行的AUTO_INCREMENT 列,则LAST_INSERT_ID() 的值不会变化(换言之, 一个不是 NULL也不是 0的值)。重点: 假如你使用单INSERT语句插入多个行,  LAST_INSERT_ID() 只返回插入的第一行产生的值。其原因是这使依靠其它服务器复制同样的 INSERT语句变得简单。 例如: mysql> USE test;
    Database changed
    mysql> CREATE TABLE t (
        ->   id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
        ->   name VARCHAR(10) NOT NULL
        -> );
    Query OK, 0 rows affected (0.09 sec)
     
    mysql> INSERT INTO t VALUES (NULL, 'Bob');
    Query OK, 1 row affected (0.01 sec)
     
    mysql> SELECT * FROM t;
    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    +----+------+
    1 row in set (0.01 sec)
     
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                1 |
    +------------------+
    1 row in set (0.00 sec)
     
    mysql> INSERT INTO t VALUES
        -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
     
    mysql> SELECT * FROM t;
    +----+------+
    | id | name |
    +----+------+
    |  1 | Bob  |
    |  2 | Mary |
    |  3 | Jane |
    |  4 | Lisa |
    +----+------+
    4 rows in set (0.01 sec)
     
    mysql> SELECT LAST_INSERT_ID();
    +------------------+
    | LAST_INSERT_ID() |
    +------------------+
    |                2 |
    +------------------+
    1 row in set (0.00 sec)
    虽然第二个问询将3 个新行插入 t, 对这些行的第一行产生的 ID 为 2, 这也是 LAST_INSERT_ID()返回的值。假如你使用 INSERT IGNORE而记录被忽略,则AUTO_INCREMENT 计数器不会增量,而 LAST_INSERT_ID() 返回0, 这反映出没有插入任何记录。 若给出作为到LAST_INSERT_ID()的参数expr ,则参数的值被函数返回,并作为被LAST_INSERT_ID()返回的下一个值而被记忆。这可用于模拟序列:创建一个表,用来控制顺序计数器并使其初始化: 
    o                     mysql> CREATE TABLE sequence (id INT NOT NULL);o                     mysql> INSERT INTO sequence VALUES (0);使用该表产生这样的序列数 : 
    o                     mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);o                     mysql> SELECT LAST_INSERT_ID();UPDATE 语句会增加顺序计数器并引发向LAST_INSERT_ID()  的下一次调用,用来返回升级后的值。 SELECT 语句会检索这个值。  mysql_insert_id() C API函数也可用于获取这个值。 见25.2.3.36节,“mysql_insert_id()”. 你可以不用调用LAST_INSERT_ID()而产生序列,但这样使用这个函数的效用在于 ID值被保存在服务器中,作为自动产生的值。它适用于多个用户,原因是多个用户均可使用 UPDATE语句并用SELECT语句(或mysql_insert_id()),得到他们自己的序列值,而不会影响其它产生他们自己的序列值的客户端或被其它产生他们自己的序列值的客户端所影响。 注意, mysql_insert_id() 仅会在INSERT 和UPDATE语句后面被升级, 因此你不能在执行了其它诸如SELECT或 SET 这样的SQL语句后使用 C API 函数来找回 LAST_INSERT_ID(expr) 对应的值。