如何让mysql的最后一个插入ID与事务一起工作? +交易问题

时间:2013-02-28 16:56:27

标签: mysql codeigniter transactions pdo

两部分问题:

  1. 在我的CodeIgniter脚本中,我正在启动一个事务,然后插入一行,将insert_id()设置为php变量,使用新ID作为外键将更多行插入另一个表中,然后我承诺一切。

    所以我的问题是:如果在结束事务之前一切都没有提交,如果没有插入任何内容,mysql如何能够返回最后一个插入ID?我的脚本(几乎)完美地工作,新ID在后续查询中使用。

    (我说“差不多”因为,使用PDO mysql驱动程序,有时第一个应该返回insert_id()的插入是重复的 - 它被插入两次。任何想法为什么会这样?是否与获取最后一个ID?如果使用mysqli或mysql驱动程序,它永远不会发生。)

  2. 我首先编写没有事务的脚本,所以我有代码检查一路上的mysql错误,例如:

    if(!$this->db->insert($table, $data)) {
        //log message here
    }
    

    一旦我将所有mysql代码包装在事务中,这对mysql进程有何影响?它没有引起任何明显的错误(希望与上述问题无关),但是应该将其删除吗?

  3. 谢谢。

1 个答案:

答案 0 :(得分:29)

回答你的第一个问题......

使用事务时,就您的连接而言,您的查询会正常执行。您可以选择提交,保存这些更改或回滚,还原所有更改。请考虑以下伪代码:

insert into number(Random_number) values (rand()); 
select Random_number from number where Number_id=Last_insert_id();

// PHP

if($num < 1)
   $this->db->query('rollback;'); // This number is too depressing.
else
   $this->db->query('commit;'); // This number is just right.

生成的随机数可以在提交之前读取,以确保它在保存之前适合所有人查看(例如提交和解锁行)。

如果PDO驱动程序不工作,请考虑使用mysqli驱动程序。如果这不是一个选项,您始终可以使用查询'select last_insert_id()作为id;'而不是$ this-&gt; db-&gt; insert_id()函数。

要回答第二个问题,如果要插入或更新其他模型将要更新或读取的数据,请务必使用事务。例如,如果列'Number_remaining'设置为1,则可能发生以下问题。

Person A reads 1
Person B reads 1
Person A wins $1000!
Person A updates 1 to be 0
Person B wins $1000!
Person B updates 0 to be 0

在相同情况下使用交易会产生这样的结果:

  

人A开始交易
人A从中读取'1'   Number_remaining
(如果使用select for update,该行现已锁定)
人B.   尝试读取Number_remaining - 强制等待
人A获胜   $ 1000
人A更新1为0
人A提交人B   读数0
人B不赢1000美元因人B哭泣

您也可以阅读transaction isolation levels

小心死锁,在这种情况下会发生:

  

人A读取第1行(select ... for update
人B读取行   2(select ... for update
人A试图阅读第2行,   被迫等待人B试图读第1行,被迫等待
  人A达到innodb_lock_wait_timeout(默认为50秒)并且是   断开连接的人B读取第1行并正常继续

最后,由于Person B可能已达到PHP的max_execution_time,因此当前查询将独立于PHP完成执行,但不会再收到任何查询。如果这是具有autocommit = 0的事务,则在切断与PHP服务器的连接时,查询将自动回滚。