【问题标题】:How to get the next auto-increment id in mysql如何在mysql中获取下一个自动增量ID
【发布时间】:2011-10-09 08:06:03
【问题描述】:

如何在mysql中获取下一个id插入到表中

INSERT INTO payments (date, item, method, payment_code)
VALUES (NOW(), '1 Month', 'paypal', CONCAT("sahf4d2fdd45", id))

【问题讨论】:

  • 使用auto_increment
  • 你想要next id,还是你当前插入的行的id?也就是支付码末尾的id应该是支付码所在行的id吗?
  • 我当前插入的行的id
  • 在这种情况下,请在检索值时连接它们,而不是在插入它们时连接它们。这样会容易得多,并且您排除了获取错误的 ID,或者必须运行更新 - 想想如果您刚刚插入的行在更新有机会运行之前被另一个客户端请求会发生什么:客户端最终会得到一个无效的付款代码。在低流量系统上,这可能不会发生,但我看不出冒险的意义。
  • ...或者正如@binaryLV 指出的那样,资源锁定也可能解决问题。见:dev.mysql.com/doc/refman/5.5/en/lock-tables.html

标签: mysql sql


【解决方案1】:

你可以使用

SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'table_name'
AND table_schema = DATABASE( ) ;

或者如果你不想使用 information_schema,你可以使用这个

SHOW TABLE STATUS LIKE 'table_name'

【讨论】:

  • 感谢前两个选项。但第三个只是从 PHP 调用的第二个。不知道是什么让大型数据库更快...
  • @GerardONeill 删除了它
  • 因为缓存用于从 information_schema.tables 中检索数据,所以这个解决方案不再适用于 mysql 8。
  • @Bruno 你能发个参考吗?
  • 这个官方文档声明 TABLES.AUTO_INCREMENT 被缓存 dev.mysql.com/doc/refman/8.0/en/… 。 Mysql博客也有几篇关于它的帖子,但他们提到的系统变量似乎已经过时了:mysqlserverteam.com/…mysqlserverteam.com/…
【解决方案2】:

您可以通过以下方式获得下一个自动增量值:

SHOW TABLE STATUS FROM tablename LIKE Auto_increment
/*or*/
SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'tablename'

请注意,您应该使用它来更改表,而是使用 auto_increment 列自动执行此操作。
问题是last_insert_id() 具有追溯性,因此可以在当前连接内得到保证。
这个婴儿是预期的,因此每个连接都不是唯一的,不能依赖。
只有在单连接数据库中才能工作,但是今天的单连接数据库有明天变成多连接数据库的习惯。

见:SHOW TABLE STATUS

【讨论】:

  • 我没有投反对票,但尝试使用最后一个自动递增值的问题在于,当您开始使用它时,它可能不是最后一个 - 无论多快执行 SELECT 和随后的 INSERT。
  • @binaryLV:SELECT 和 INSERT 之间的差距越小,值发生变化的机会就越小,但并不完全排除它。想象一个每分钟对数据库有数千次点击的系统 - 值发生变化的机会急剧增加。如果作为单个查询完成,表或行锁定可能会阻止这种情况,但这依赖于数据库引擎的特定行为,可能没有很好的文档记录。如果我也有的话,我会选择随后的UPDATE。但我宁愿在显示时将两者连接起来,省去所有的麻烦。
  • 基本上需要看下一个自增会是什么。这是最好的选择,因为我还没有插入任何东西!只要确保在调用它之前锁定将插入记录的表并稍后使用它(当然是在你解锁之后!)例如。锁定表 t1 读取;
  • SHOW TABLE STATUS 预计在FROM'table name pattern' 之后看到database nameLIKE 之后。
  • 因为缓存用于从 information_schema.tables 中检索数据,所以此解决方案不再适用于 mysql 8。
【解决方案3】:

这将返回 MySQL 数据库的自动增量值,我没有检查其他数据库。请注意,如果您使用任何其他数据库,查询语法可能会有所不同。

SELECT AUTO_INCREMENT 
FROM information_schema.tables
WHERE table_name = 'your_table_name'
     and table_schema = 'your_database_name';

SELECT AUTO_INCREMENT 
FROM information_schema.tables
WHERE table_name = 'your_table_name'
     and table_schema = database();

【讨论】:

  • SELECT AUTO_INCREMENT FROM information_schema.tables WHERE table_name = 'your_table_name' and table_schema = 'your_database_name';
【解决方案4】:

最佳答案使用 PHP MySQL_ 作为解决方案,我想我会分享一个更新的 PHP MySQLi_ 解决方案来实现这一点。此示例中没有错误输出!

$db = new mysqli('localhost', 'user', 'pass', 'database');
$sql = "SHOW TABLE STATUS LIKE 'table'";
$result=$db->query($sql);
$row = $result->fetch_assoc();

echo $row['Auto_increment'];

踢出表格中出现的下一个自动增量。

【讨论】:

  • 因为缓存用于从 information_schema.tables 中检索数据,所以这个解决方案不再适用于 mysql 8。
【解决方案5】:

在 PHP 中你可以试试这个:

$query = mysql_query("SELECT MAX(id) FROM `your_table_name`");
$results = mysql_fetch_array($query);
$cur_auto_id = $results['MAX(id)'] + 1;

$result = mysql_query("SHOW TABLE STATUS WHERE `Name` = 'your_table_name'");
$data = mysql_fetch_assoc($result);
$next_increment = $data['Auto_increment'];

【讨论】:

  • 请记住,如果删除了具有最高 id 的记录,则使用第一种方法,然后您将创建一个新的记录,该记录的 id 是以前删除的记录。
  • 如果之前的键在另一个表中使用并且仍然保留在那里,你最终会得到非常奇怪的魔法
  • 如果你删除最后插入的记录,第一个返回错误的 id,
【解决方案6】:

在您的 SQL 查询中使用 LAST_INSERT_ID()

或者

您也可以使用mysql_insert_id() 来使用 PHP 获取它。

【讨论】:

  • @Sarfraz:问题是关于 NEXT id 而不是 LAST 正如你所说的提到LAST_INSERT_ID()
  • 如果表中的行被删除,最大值将是错误的
  • 只是 17 年的一个注释 - 不推荐使用 mysql* 函数 - 以上可以通过 mysqli_insert_id 完成
  • 谁将此标记为答案?问题是关于下一个插入 ID 不是最后一个。
【解决方案7】:

解决方案:

CREATE TRIGGER `IdTrigger` BEFORE INSERT ON `payments`
  FOR EACH ROW
BEGIN

SELECT  AUTO_INCREMENT Into @xId
    FROM information_schema.tables
    WHERE 
    Table_SCHEMA ="DataBaseName" AND
    table_name = "payments";

SET NEW.`payment_code` = CONCAT("sahf4d2fdd45",@xId);

END;

“DataBaseName”是我们数据库的名称

【讨论】:

    【解决方案8】:

    简单的查询就可以了 SHOW TABLE STATUS LIKE 'table_name'

    【讨论】:

      【解决方案9】:

      我建议重新考虑你在做什么。我从来没有经历过一个需要特殊知识的用例。下一个 id 是一个非常特殊的实现细节,我不会指望它是 ACID 安全的。

      做一个简单的交易,用最后一个 id 更新你插入的行:

      BEGIN;
      
      INSERT INTO payments (date, item, method)
           VALUES (NOW(), '1 Month', 'paypal');
      
      UPDATE payments SET payment_code = CONCAT("sahf4d2fdd45", LAST_INSERT_ID())
           WHERE id = LAST_INSERT_ID();
      
      COMMIT;
      

      【讨论】:

      • 我可以告诉一个这样的用例,我正在尝试诊断生产问题,所以我需要确定表中的最后一行是否真的是最后一行,或者是否添加了一个在不知何故被删除之后,表中有一个 auto_increment 字段,因此通过查找此信息,我可以断定该行是否已删除或从未添加。
      • 这可能对您有用,但我不会依赖它,因为我认为您对此没有任何保证:dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html“当 AUTO_INCREMENT 列是多个-列索引),如果您删除任何组中具有最大 AUTO_INCREMENT 值的行,则会重用 AUTO_INCREMENT 值。"
      • 谢谢,有用的信息,也可以根据您的共享链接 auto_increment 可以通过手动插入数字来重置,所以是不可靠的。
      【解决方案10】:

      插入时不能使用 ID,也不需要它。当您插入该记录时,MySQL 甚至不知道 ID。您可以将"sahf4d2fdd45" 保存在payment_code 表中,然后再使用idpayment_code

      如果您确实需要您的 payment_code 在其中包含 ID,请更新插入后的行以添加 ID。

      【讨论】:

      • +1 为了更明确一点:如果您从列中获取“最新”值,则只能保证在您获取它的确切时刻它是最新值。当您在后续插入中使用该值时,它可能不是最新值。在自动增量列的情况下,总是有可能在您检索 id 的时间和您将其插入其他位置的时间之间添加了另一个值。如果您要引用刚刚插入的行,使用 LAST_INSERT_ID() 就可以了。如果您试图确保一个唯一的值,它不是。
      • @cularis,MySQL 确实知道下一个 auto_increment id,它列在 information_schema.tables 表中。
      • @faressoft:如果想法是有一个包含唯一字符串的支付代码加上包含该支付代码的行的 ID,只需在检索该行时将两者结合起来 - 或者使用SELECT ... CONCAT(payment_code, id),或在您的应用程序代码中。您甚至可以将 SELECT 包装在 VIEW 中,这样您就可以始终返回正确的值,而不必担心应用程序中每个 SELECT 中的 CONCAT。
      【解决方案11】:

      您需要下一个增量 ID 做什么?

      MySQL 只允许每张表有一个自增字段,并且必须是主键才能保证唯一性。

      请注意,当您获得下一个插入 ID 时,它可能在您使用它时不可用,因为您拥有的值仅在该事务的范围内。因此,根据您数据库上的负载,该值可能在下一个请求到来时已被使用。

      我建议您检查您的设计,以确保您不需要知道接下来要分配哪个自动增量值

      【讨论】:

      • 假设应用程序需要 ID 不是一个好主意。像我目前正在处理的应用程序需要下一个增量 ID,并且检索到的值没有被分配给另一个脚本的危险。
      【解决方案12】:

      您必须先连接到 MySQL 并选择一个数据库,然后才能执行此操作

      $table_name = "myTable"; 
      $query = mysql_query("SHOW TABLE STATUS WHERE name='$table_name'"); 
      $row = mysql_fetch_array($query); 
      $next_inc_value = $row["AUTO_INCREMENT"];  
      

      【讨论】:

        【解决方案13】:

        对于 MySQL 8,使用 SHOW CREATE TABLE 检索下一个自动增量插入 id:

        SHOW CREATE TABLE mysql.time_zone

        结果:

        CREATE TABLE `time_zone` (
          `Time_zone_id` int unsigned NOT NULL AUTO_INCREMENT,
          `Use_leap_seconds` enum('Y','N') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'N',
          PRIMARY KEY (`Time_zone_id`)
        ) ENGINE=InnoDB AUTO_INCREMENT=1784 DEFAULT CHARSET=utf8 STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC COMMENT='Time zones'
        

        查看返回查询最后一行的AUTO_INCREMENT=1784

        与最后插入的值比较: select max(Time_zone_id) from mysql.time_zone

        结果:

        +-------------------+
        | max(Time_zone_id) |
        +-------------------+
        |              1783 |
        +-------------------+
        

        在 MySQL v8.0.20 上测试。

        【讨论】:

          【解决方案14】:

          使用“mysql_insert_id()”。 mysql_insert_id() 作用于最后执行的查询,确保在生成值的查询之后立即调用 mysql_insert_id()。

          以下是使用示例:

          <?php
              $link = mysql_connect('localhost', 'username', 'password');
          if (!$link) {
              die('Could not connect: ' . mysql_error());
          }
          mysql_select_db('mydb');
          
          mysql_query("INSERT INTO mytable  VALUES('','value')");
          printf("Last inserted record has id %d\n", mysql_insert_id());
              ?>
          

          我希望上面的例子有用。

          【讨论】:

          • 谢谢我知道了。
          【解决方案15】:
          SELECT id FROM `table` ORDER BY id DESC LIMIT 1
          

          虽然我怀疑它的生产力,但它是 100% 可靠的

          【讨论】:

          • 我也同意这是最简单的方法。不知道你为什么被否决,但我会用赞成票来抵消。
          • 我没有提到事务的必要性,如果你不将它包装在事务中,这个代码很糟糕,它尽快满足实际加载。
          • 如果最后一行被删除了怎么办?或者多个最新的行已被删除?
          • 除非您明确指定,否则不会使用非问题、已释放的密钥
          【解决方案16】:

          使用ravi404的答案:

          CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
              RETURNS BIGINT
              LANGUAGE SQL
              NOT DETERMINISTIC
              CONTAINS SQL
              SQL SECURITY DEFINER
              COMMENT ''
          BEGIN
          
              DECLARE Value BIGINT;
          
              SELECT
                  AUTO_INCREMENT INTO Value
              FROM
                  information_schema.tables
              WHERE
                  table_name = TableName AND
                  table_schema = DATABASE();
          
              RETURN Value;
          
          END
          

          在您的插入查询中使用,以创建 SHA1 哈希。例如:

          INSERT INTO
              document (Code, Title, Body)
          VALUES (                
              sha1( getAutoincrementalNextval ('document') ),
              'Title',
              'Body'
          );
          

          【讨论】:

          • 这总是有效吗?如果两个插入同时发生,是否存在竞争条件?
          【解决方案17】:

          如果没有返回正确的 AUTO_INCREMENT,请尝试:

          ANALYZE TABLE `my_table`;
          SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE (TABLE_NAME = 'my_table');
          

          此清除表缓存,在 BD 中

          【讨论】:

            【解决方案18】:

            改进@ravi404,以防您的自动增量偏移量不是 1:

            SELECT (`auto_increment`-1) + IFNULL(@@auto_increment_offset,1) 
            FROM INFORMATION_SCHEMA.TABLES
            WHERE table_name = your_table_name
            AND table_schema = DATABASE( );
            

            (auto_increment-1) : db 引擎似乎总是考虑偏移量 1。所以你需要放弃这个假设,然后添加 @@auto_increment_offset 的可选值,或者默认为 1:IFNULL(@@auto_increment_offset ,1)

            【讨论】:

              【解决方案19】:

              对我来说它很有效,而且看起来很简单:

               $auto_inc_db = mysql_query("SELECT * FROM my_table_name  ORDER BY  id  ASC ");
               while($auto_inc_result = mysql_fetch_array($auto_inc_db))
               {
               $last_id = $auto_inc_result['id'];
               }
               $next_id = ($last_id+1);
              
              
               echo $next_id;//this is the new id, if auto increment is on
              

              【讨论】:

              • 完全没有必要重复分配$last_id,而您可以只使用DESC。你的 while 块做了很多无用的工作。
              • 是的,对...我刚刚意识到它并不完美...:( end one可以重复id,如果它之前被删除... :(
              【解决方案20】:
              mysql_insert_id();
              

              就是这样:)

              【讨论】:

                猜你喜欢
                • 2016-01-08
                • 2020-01-29
                • 1970-01-01
                • 2010-11-25
                • 2012-07-13
                • 1970-01-01
                • 1970-01-01
                • 2018-03-24
                • 2012-12-19
                相关资源
                最近更新 更多