我有一个表字段类型varchar(36),我想通过mysql动态生成它,所以我使用了这段代码:
$sql_code = 'insert into table1 (id, text) values (uuid(),'some text');';
mysql_query($sql_code);
如何在插入记录后立即检索生成的uuid?
答案 0 :(得分:23)
char(36)
更好你做不到。唯一的解决方案是执行2个独立的查询:
SELECT UUID()
INSERT INTO table1 (id, text) VALUES ($uuid, 'text')
其中$ uuid是第一步检索到的值。
答案 1 :(得分:10)
您可以使用SQL触发器完成所需的一切。以下SQL在tablename.table_id
上添加了一个触发器,以便在插入时自动创建主键UUID,然后将新创建的ID存储到SQL变量中以便以后检索:
CREATE TRIGGER `tablename_newid`
AFTER INSERT ON `tablename`
FOR EACH ROW
BEGIN
IF ASCII(NEW.table_id) = 0 THEN
SET NEW.table_id = UNHEX(REPLACE(UUID(),'-',''));
END IF;
SET @last_uuid = NEW.table_id;
END
作为奖励,它将二进制形式的UUID插入二进制(16)字段以节省存储空间并大大提高查询速度。
编辑:触发器应该在插入自己的UUID之前检查现有的列值,以便模仿为MySQL中的表主键提供值的能力 - 如果没有这个,传入的任何值将始终被覆盖触发。该示例已更新为使用ASCII() = 0
检查INSERT中是否存在主键值,该值将检测二进制字段的空字符串值。
编辑2:在评论here之后,我已经向我指出,即使行插入失败,使用BEFORE INSERT
也会设置@last_uuid
变量的效果。我已经更新了使用AFTER INSERT
的答案 - 虽然我觉得这在一般情况下是一个非常好的方法,但在集群或复制数据库下可能存在行复制的问题。如果有人知道,我也会喜欢!
要重新读取新行的插入ID,只需运行SELECT @last_uuid
。
在查询和读取此类二进制值时,MySQL函数HEX()
和UNHEX()
将非常有用,将以十六进制表示法编写查询值(以0x
开头)。鉴于应用于table1的这种类型的触发器,原始答案的php端代码将是:
// insert row
$sql = "INSERT INTO table1(text) VALUES ('some text')";
mysql_query($sql);
// get last inserted UUID
$sql = "SELECT HEX(@last_uuid)";
$result = mysql_query($sql);
$row = mysql_fetch_row($result);
$id = $row[0];
// perform a query using said ID
mysql_query("SELECT FROM table1 WHERE id = 0x" . $id);
跟进以回复@ina's comment:
UUID不是字符串,即使MySQL选择代表它。它是原始形式的二进制数据,这些破折号只是MySQL友好的代表它的方式。
UUID最有效的存储是将其创建为UNHEX(REPLACE(UUID(),'-',''))
- 这将删除该格式并将其转换回二进制数据。这些函数会使原始插入更慢,但是对于16字节二进制字段而言,对该键或列进行的所有后续比较将比36字符字符串快得多。
首先,字符数据需要解析和本地化。进入查询引擎的任何字符串通常都会自动与数据库的字符集进行整理,并且在查询之前,甚至会对所有字符串数据运行CONVERT()
一些API(wordpress)。二进制数据没有这种开销。另一方面,char(36)
实际上分配了36个字符,这意味着(如果您的数据库是UTF-8),每个字符可能与3 or 4 bytes一样长,具体取决于版本您正在使用的MySQL。所以char(36)
可以在36字节(如果它完全由低ASCII字符组成)到144(如果完全由高阶UTF8字符组成)的范围内。这比我们为二进制字段分配的16个字节大多。
对此数据执行的任何逻辑都可以使用UNHEX()
完成,但最好通过将查询中的数据转义为十六进制(前缀为0x
)来实现。这与读取字符串一样快,在运行中转换为二进制并直接分配给相关查询或单元格。非常快。
读取数据的速度稍慢 - 如果客户端API不能很好地处理二进制数据,则必须对从查询中读取的所有二进制数据调用HEX()
以获得有用的格式(特别是PHP通常会确定二进制字符串=== null
并且如果在没有先调用bin2hex()
,base64_encode()
或类似的情况下进行操作的情况下将会破坏它们 - 但这个开销与字符整理一样小,更重要的是仅被调用在实际的单元格SELECT
上,并不是查询结果内部计算中涉及的所有单元格。
当然,所有这些小的速度增加都是非常小的,而其他区域导致小幅下降 - 但是当你添加它们时,所有binary
仍然排在最前面,当你考虑用例和一般情况时'读>写'原则它真的很闪耀。
......这就是为什么binary(16)
优于char(36)
。
答案 2 :(得分:5)
实际上非常简单 你可以将它传递给mysql,它将返回插入的id。
set @id=UUID();
insert into <table>(<col1>,<col2>) values (@id,'another value');
select @id;
答案 3 :(得分:-1)
根据uuid()函数的实现方式,这是非常糟糕的编程习惯 - 如果您尝试在启用二进制日志记录的情况下(即在集群中)执行此操作,则插入将most likely fail。 Ivan的建议看起来可能会解决当前的问题 - 但是我认为这只会返回为自动增量字段生成的值 - 实际上是what the manual says。
使用uuid()有什么好处?其生成计算成本高,需要大量存储,增加了查询数据的成本,并且不具有加密安全性。请改用序列发生器或自动增量。
无论你使用序列生成器还是uuid,如果你必须使用它作为数据库上唯一的唯一键,那么你需要首先分配值,将其读回到phpland并将值嵌入/绑定为后续插入查询的文字。