在插入php后获取生成的uuid

在插入php后获取生成的uuid,php,mysql,uuid,Php,Mysql,Uuid,我有一个表字段类型varchar(36),我想通过mysql动态生成它,所以我使用了以下代码: $sql_code = 'insert into table1 (id, text) values (uuid(),'some text');'; mysql_query($sql_code); 如何在插入记录后立即检索生成的uuid char(36)更好 你不能。唯一的解决方案是执行两个单独的查询: 选择UUID() 将值($uuid,'text')插入表1(id,text) 其中,$uuid

我有一个表字段类型varchar(36),我想通过mysql动态生成它,所以我使用了以下代码:

$sql_code = 'insert into table1 (id, text) values (uuid(),'some text');';
mysql_query($sql_code);
如何在插入记录后立即检索生成的uuid

  • char(36)
    更好
  • 你不能。唯一的解决方案是执行两个单独的查询:

    • 选择UUID()
    • 将值($uuid,'text')插入表1(id,text)
  • 其中,$uuid是在第一步中检索到的值。

    这取决于uuid()函数的实现方式,这是一种非常糟糕的编程实践-如果您尝试在启用二进制日志记录的情况下(即在集群中)执行此操作,则插入将失败。Ivan的建议似乎可以解决眼前的问题——但是我认为这只返回为自动递增字段生成的值——事实上,这是正确的

    使用uuid()还有什么好处?生成它的计算成本很高,需要大量存储,增加了查询数据的成本,并且在加密方面不安全。改用序列生成器或自动增量


    无论您使用的是序列生成器还是uuid,如果必须将其用作数据库上唯一的键,则需要首先分配值,将其读回phpland,并将该值作为文本嵌入/绑定到后续的insert查询。

    您可以使用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:在注释之后,有人向我指出,即使行插入失败,在插入之前使用
    也可以设置
    @last\u uuid
    变量。我已经更新了我的答案,在插入后使用
    ——虽然我觉得这在一般情况下是一种非常好的方法,但在集群或复制数据库下,行复制可能会出现问题。如果有人知道,我也很乐意

    要读取新行的插入ID,只需运行
    SELECT@last\uuid

    当查询和读取这样的二进制值时,MySQL函数
    HEX()
    UNHEX()
    将非常有用,用十六进制表示法编写查询值(前面是
    0x
    )。如果将这种类型的触发器应用于表1,则原始答案的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);
    
    针对以下问题采取后续行动:

    UUID不是字符串,即使MySQL选择将其表示为字符串。它是原始形式的二进制数据,这些破折号只是MySQL对您表示它的友好方式

    UUID最有效的存储是将其创建为
    UNHEX(替换(UUID(),'-','')
    ——这将删除该格式并将其转换回二进制数据。这些函数将使原始插入速度变慢,但在16字节二进制字段上对该键或列执行的所有后续比较将比36个字符的字符串快得多


    首先,字符数据需要解析和本地化。进入查询引擎的任何字符串通常都会根据数据库的字符集自动进行整理,一些API(wordpress)甚至会在查询之前对所有字符串数据运行
    CONVERT()
    。二进制数据没有这种开销。另一方面,您的
    char(36)
    实际上分配了36个字符,这意味着(如果您的数据库是UTF-8),根据您使用的MySQL的版本,每个字符的长度可以是相同的。因此
    char(36)
    的范围可以从36字节(如果它完全由低ASCII字符组成)到144字节(如果它完全由高阶UTF8字符组成)。这比我们为二进制字段分配的16个字节大得多

    对该数据执行的任何逻辑都可以使用
    UNHEX()
    ,但最好是将查询中的数据转义为十六进制,前缀为
    0x
    。这与读取字符串一样快,可以动态转换为二进制,并直接分配给相关查询或单元格。非常快。 读取数据的速度稍慢-如果客户端API不能很好地处理二进制数据,则必须对从查询中读取的所有二进制数据调用
    HEX()
    ,以使其成为有用的格式(PHP在paricular中通常会确定二进制字符串
    ==null
    ,如果不首先调用
    bin2hex>而对其进行操作,则会将其破坏()
    base64_encode()
    或类似)-但此开销与字符排序一样小,更重要的是仅在实际单元格
    SELECT
    ed上调用,而不是查询结果内部计算中涉及的所有单元格

    当然,所有这些小的速度增长都很小,其他区域会导致小的减少——但是当你把它们全部加起来<代码>二进制仍然会出现在顶部,当你考虑用例和一般的“读>写”原则时,它真的闪闪发光。

    …这就是为什么
    binary(16)
    char(36)
    好的原因,实际上它非常简单 您可以将其传递给mysql,它将返回插入的id

    set @id=UUID();
    insert into <table>(<col1>,<col2>) values (@id,'another value');
    select @id;
    
    set@id=UUID();
    插入(,)个值(@id,'other value');
    选择@id;
    
    是否为y