站保站

服务市场
  • 网站市场
  • 单机游戏
  • 平台大厅
  • 转让市场
  • 发卡市场
  • 广告市场
  • 下载市场
  • 收录市场
  • 本站平台
    平台客服
    微信Q群



    平台微博/weibo    平台微信/公众号    平台抖音/快手   
    曝光台    保障    地图   
    上传资源 快速赚钱
    站保站    登录      |  注册  |  

    只需一步,快速开始!

     找回密码   |   协议
    热门搜索: 网站开发 App报毒 挖矿源码 代办资质

    LAST_INSERT_ID()可信吗

    • 时间:2019-05-31 09:47 编辑:老叶茶馆_ 来源: 阅读:1917
    • 扫一扫,手机访问
    摘要:

    导读

    通常我们会在执行一次INSERT后,调用LAST_INSERT_ID()获取最新的自增ID,但这么做其实并不太可靠。

    函数 LAST_INSERT_ID() 没有额外参数或表达式时,则返回一个无符号BIGINT,默认地,它返回最后一次对自增ID列INSERT后的值。
    注意,对非自增ID列INSERT结束后,调用 LAST_INSERT_ID() 是没有作用的,例如:

    
     

    [root@yejr.me]> create table tt (
    `id` int(11) NOT NULL primary key,
    `c1` int(10) unsigned NOT NULL
    )engine=innodb;

    [root@yejr.me]> insert into tt values(0,0);
    Query OK, 1 row affected (0.01 sec)

    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 0 |
    +------------------+

    在应用程序中,不少开发者会习惯调用 LAST_INSERT_ID() 函数获取最后插入的自增值,但实际上这么做并不可靠,我们来看几个例子:

    例1,插入失败时

    
     

    [root@yejr.me]> CREATE TABLE `t` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `c1` int(10) unsigned NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB;

    # 第一次插入,没问题
    [root@yejr.me]> insert into t select 0,rand()*1024;
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 1 |
    +------------------+

    # 第二次插入,也没问题
    [root@yejr.me]> insert into t select 0,rand()*1024;
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 2 |
    +------------------+

    # 第三次插入,故意制造一个重复主键,这次就不对了
    [root@yejr.me]> insert into t values(0,rand()*1024), (3, rand()*1024);
    ERROR 1062 (23000): Duplicate entry '3' for key 'PRIMARY'
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 3 |
    +------------------+

    # 表中实际只有两条记录
    [root@yejr.me]> select * from t;
    +----+-----+
    | id | c1 |
    +----+-----+
    | 1 | 784 |
    | 2 | 574 |
    +----+-----+
    2 rows in set (0.00 sec)

    例子2,同时多次插入时

    多个insert时,返回第二个insert值,例如:

    
     

    # 现在表里有3条记录
    [root@yejr.me]> select * from t;
    +----+-----+
    | id | c1 |
    +----+-----+
    | 1 | 784 |
    | 2 | 574 |
    | 5 | 681 |
    +----+-----+
    3 rows in set (0.00 sec)

    # 一次性再插入3条记录
    [root@yejr.me]> insert into t values
    (0,rand()*1024), (0, rand()*1024), (0,rand()*1024);

    # 获取到的 last_insert_id() 值却是6,显然“不太符合预期”
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 6 |
    +------------------+

    [root@yejr.me]> select * from t;
    +----+-----+
    | id | c1 |
    +----+-----+
    | 1 | 784 |
    | 2 | 574 |
    | 5 | 681 |
    | 6 | 841 |
    | 7 | 112 |
    | 8 | 87 |
    +----+-----+
    6 rows in set (0.00 sec)

    例3,当 LAST_INSERT_ID() 带有参数时

    
     

    # 清空重来
    [root@yejr.me]> truncate table t;

    # 插入1条新记录
    [root@yejr.me]> insert into t select 0,rand()*1024;

    # 查看 last_insert_id(), 符合预期
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 1 |
    +------------------+

    [root@yejr.me]> select * from t;
    +----+-----+
    | id | c1 |
    +----+-----+
    | 1 | 730 |
    +----+-----+

    # 调用 last_insert_id() 时增加表达式
    [root@yejr.me]> select last_insert_id(id+2) from t;
    +----------------------+
    | last_insert_id(id+2) |
    +----------------------+
    | 3 |
    +----------------------+

    # 再看 last_insert_id() 的值,好像“又不符合预期”了
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 3 |
    +------------------+

    # 插入1条新纪录
    [root@yejr.me]> insert into t select 0,rand()*1024;

    # 再看 last_insert_id() 的值,好像“又回到正轨”了
    [root@yejr.me]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 2 |
    +------------------+

    [root@yejr.me]> select * from t;
    +----+-----+
    | id | c1 |
    +----+-----+
    | 1 | 730 |
    | 2 | 600 |
    +----+-----+
    2 rows in set (0.00 sec)

    通过几个例子,我们能看到调用 last_insert_id() 函数想获取表中自增列最大值其实并不可靠,如果需要构建一个sequence表,最好还是每次都调用 max() 函数获取最大值才行。

    附带MySQL版本信息:

    
     

    [root@yejr.me]> \s
    ...
    Server version: 8.0.15 MySQL Community Server - GPL
    ...

    参考资料

    MySQL手册 https://dev.mysql.com/doc/refman/8.0/en/information-functions.html#function_last-insert-id

    • 全部评论(0)
    • 最新

    信息加载中,请等待

    微信客服(速回)

    微信客服(慢回)



    企业微信客服二维码
    联系我们
    平台客服: 平台QQ客服

    平台电话:400电话迁移中!

    平台邮箱:28292383@qq.com

    工作时间:周一至周五:早10:00 晚:18:00

    营业执照     网站ICP备案:鲁ICP备20027607号-1     鲁公网安备:37068702000078号     增值电信业务经营许可证、在线数据与交易处理业务许可证:鲁B2-20200681      © 2016-2024 站保站  https://www.zhanbaozhan.com/ 版权所有!      平台规范:   关于我们   广告合作   隐私条款   免责声明   法律声明   服务条款   网站地图   平台工单!