(MySQL,PHP)如何在插入数据之前获取auto_increment字段的值?

11

我正在将图片文件上传至存储服务器。在上传之前,我应该组合包含自增值的文件名(例如:12345_filename.jpg)。

我该如何在插入数据库之前获取自增值?

我只看到了一个解决方案:

  1. 插入空行
  2. 获取它的自增值
  3. 删除此行
  4. 使用步骤1中的自增值插入真实数据的行

是否有其他解决方案?

谢谢


你所提出的方法不好;如果另一个用户在3和4之间开始了该路径怎么办?插入行,获取ID,然后更新该行。 - Erik
2
如果另一个用户在3和4之间开始操作,因为此自动增量值已经被保留,并且不会被mysql再次分配,所以不会发生任何事情。更新很好,但如果上传失败,我应该注意删除空行。 - Kirzilla
8个回答

14

自增值是在插入操作完成后由数据库自动生成的,这意味着您不能在实际执行插入查询之前获取它。

您提出的解决方案并不常用,常用的方法是:

  • 插入一些半空数据
  • 获取生成的自增值
  • 使用该自增值进行计算
  • 更新行以放置新的/完整的数据-在where子句中使用之前生成的自增值来确定要更新哪一行。

当然,作为安全预防措施,所有这些操作都必须在一个事务中进行(以确保“全有或全无”的行为)。


伪代码如下:

begin transaction
insert into your table (half empty values);
$id = get last autoincrement id
do calculations
update set data = full data where id = $id
commit transaction

2
我也不建议使用数据库行的ID作为图像文件名,以达到安全的目的。相反,可以使用类似于uniqid()的东西。 - Stephen Melrose
这确实是我的问题 - 如果您处于未提交的事务中,是否会实际获得新生成的ID? - Weasler

8

好的,试试这个:

$query = "SHOW TABLE STATUS LIKE 'tablename'";
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);
var_dump($row);

输出:

array(18) {
[...]
["Auto_increment"]=> string(4) "3847"
[...]
}

这将是您的下一个自动增量ID。

我猜原因可能是已经在这里提到过几次了:知道当前/下一个ID不能保证在实际插入时得到这个ID。 - deceze
1
是的,但如果您知道此期间不会有其他插入查询,则可以毫无问题地使用它。在我的某些项目中,我曾遇到过这种情况,可以安全地使用此方法。 - Alex
同意。如果您完全控制应用程序并且完全确定在此期间不会发生其他插入查询,则可能可用(但我认为这样的情况非常罕见)。 - Richard Knop
这应该是正确的答案。让我想知道现在的人们到底怎么了。 - stonyau
是的,对于并发连接来说不是一个好主意,但在我的情况下,这对单元测试来说还是可以的。我需要比较插入表格内容方法的结果与预期结果,而这正好能够预测我将得到的ID。 - tiomno

2
如果您正在使用PDO,这里有一个“一行代码”的解决方案:
$nextId = $db->query("SHOW TABLE STATUS LIKE 'tablename'")->fetch(PDO::FETCH_ASSOC)['Auto_increment'];

其中tablename被替换为您的表名。


1

没有解决方案。你只能在插入新行时获得自动递增的值,没了。插入和删除都无济于事,因为下一个自动递增的值会比当前的高一。由于可能有多个客户端同时访问数据库,你无法预测下一个值,因为它可能在你猜测和实际插入之间被递增。

找到另一个解决方案。要么先插入一行再稍后更新,要么为文件名生成一个与自动递增id无关的id。


0

@Pascal Martin提出了一个很好的观点。在这种情况下,我个人喜欢添加另一个ID列,其中包含一个随机的、16位数的ID(出于安全考虑,在Web应用程序和网站上也将是“公共”ID)。您可以预先设置这个随机ID,在应用程序中使用它,然后在实际创建记录时进行设置。


0

使用一个单独的表作为计数器,就像postgresql序列一样,不要在主表中使用auto_increment。


0

将 firstname 和 lastname 插入 CONTACTS1 表中,值为 ('hi',select auto_increment from information_schema.TABLES where TABLE_NAME='CONTACTS1' and TABLE_SCHEMA='test')。

其中 ID 是主键和自动编号列。


-2

虽然这已经过时了,但如果有其他人需要它。

您可以在“information_schema”表中获取此类值,例如:

select AUTO_INCREMENT from TABLES where TABLE_SCHEMA = 'You're Database' and TABLE_NAME = 'Table Name'

所以这种元数据总是存储在 Information_schema 中。


这很容易出现竞态条件。如果两个客户端同时获取一个ID,它们将获得相同的ID并有可能互相覆盖数据。如果您关心并发性(而且您应该关心),则从AUTO_INCREMENT获取的ID在分配给数据库中的行之前是无用的,因为在那一点上它不能保证是唯一的。 - cHao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接