Получить сгенерированный uuid после вставки php - PullRequest
7 голосов
/ 08 февраля 2011

У меня есть поле таблицы типа varchar (36), и я хочу, чтобы он генерировался динамически с помощью mysql, поэтому я использовал этот код:

$sql_code = 'insert into table1 (id, text) values (uuid(),'some text');';
mysql_query($sql_code);

как я могу получить сгенерированный uuid сразу после вставки записи?

Ответы [ 4 ]

23 голосов
/ 08 февраля 2011
  1. char(36) лучше
  2. вы не можете. Единственное решение - выполнить 2 отдельных запроса:

    • SELECT UUID()
    • INSERT INTO table1 (id, text) VALUES ($uuid, 'text')

где $ uuid - значение, полученное на 1-м шаге.

10 голосов
/ 14 декабря 2011

С помощью триггеров SQL вы можете делать все, что вам нужно. Следующий SQL добавляет триггер на tablename.table_id для автоматического создания UUID первичного ключа при вставке, а затем сохраняет вновь созданный идентификатор в переменную 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), чтобы сэкономить место на диске и значительно увеличить скорость запроса.

edit: триггер должен проверить существующее значение столбца перед вставкой собственного UUID, чтобы имитировать возможность предоставления значений для первичных ключей таблицы в MySQL - без этого любые передаваемые значения всегда будут переопределены триггер. Пример был обновлен для использования ASCII() = 0 для проверки существования значения первичного ключа в INSERT, который будет обнаруживать пустые строковые значения для двоичного поля.

edit 2: после комментария здесь с тех пор мне было указано, что использование BEFORE INSERT приводит к установке переменной @last_uuid, даже если вставка строки завершается неудачно. Я обновил свой ответ, чтобы использовать AFTER INSERT - хотя я чувствую, что это совершенно хороший подход в общих обстоятельствах, у него могут быть проблемы с репликацией строк в кластеризованных или реплицируемых базах данных. Если кто-нибудь знает, я бы тоже с удовольствием!

Чтобы прочитать ID вставки новой строки обратно, просто запустите SELECT @last_uuid.

При запросе и чтении таких двоичных значений функции MySQL HEX() и UNHEX() будут очень полезны, так же как и запись значений вашего запроса в шестнадцатеричном формате (с предшествующим 0x). Код стороны php для вашего исходного ответа, учитывая этот тип триггера, примененного к table1, будет:

// 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 :

UUID не является строкой, даже если MySQL решит представить его как таковой. Это двоичные данные в необработанном виде, и эти черточки являются просто дружественным способом представления их MySQL.

Наиболее эффективное хранилище для UUID - создать его как UNHEX(REPLACE(UUID(),'-','')) - это удалит это форматирование и преобразует его обратно в двоичные данные. Эти функции сделают оригинальную вставку медленнее, но все последующие сравнения, которые вы выполняете для этого ключа или столбца, будут намного быстрее для 16-байтового двоичного поля, чем для 36-символьной строки.

Во-первых, символьные данные требуют анализа и локализации. Любые строки, поступающие в механизм запросов, как правило, автоматически сопоставляются с набором символов базы данных, а некоторые API (вспоминается wordpress) даже запускают CONVERT() для всех строковых данных перед запросом. Двоичные данные не имеют этих накладных расходов. С другой стороны, ваш char(36) фактически выделяет 36 символов , что означает (если ваша база данных UTF-8), каждый символ может быть длиной до 3 или 4 байта в зависимости от версия MySQL, которую вы используете. Таким образом, char(36) может варьироваться от 36 байтов (если он полностью состоит из символов низкого ASCII) до 144, если он полностью состоит из символов UTF8 высокого порядка. Это на намного больше, чем 16 байтов, которые мы выделили для нашего двоичного поля.

Любую логику, выполняемую с этими данными, можно выполнить с помощью UNHEX(), но лучше это сделать, просто экранируя данные в запросах в шестнадцатеричном виде с префиксом 0x. Это так же быстро, как чтение строки, на лету преобразуется в двоичный файл и напрямую назначается запросу или ячейке. Очень быстро. Считывание данных происходит немного медленнее - вам нужно вызвать HEX() для всех двоичных данных, считанных из запроса, чтобы получить их в полезном формате, если ваш клиентский API плохо справляется с двоичными данными (PHP, в частности, обычно определяет, что двоичные строки === null и прервут их, если ими манипулировать без предварительного вызова bin2hex(), base64_encode() или подобного) - но эти издержки примерно такие же минимальные, как сопоставление символов, и, что более важно, вызываются только в фактические ячейки не все ячейки участвуют во внутренних вычислениях результата запроса.

Так что, конечно, все эти небольшие увеличения скорости очень минимальны, а другие области приводят к небольшому уменьшению - но когда вы добавляете их все, binary все равно выходит на первое место, и когда вы рассматриваете варианты использования и общие чтения> пишет, что принцип действительно сияет.

... и поэтому binary(16) лучше, чем char(36).

5 голосов
/ 30 октября 2014

На самом деле это довольно просто, вы можете передать это mysql, и он вернет вставленный идентификатор.

set @id=UUID();
insert into <table>(<col1>,<col2>) values (@id,'another value');
select @id;
0 голосов
/ 08 февраля 2011

В зависимости от того, как реализована функция uuid (), это очень плохая практика программирования - если вы попытаетесь сделать это с включенным двоичным журналированием (т. Е. В кластере), тогда вставка будет , скорее всего, ошибка, Предложение Ивана выглядит так, как будто это может решить непосредственную проблему - однако я думал, что это вернуло только значение, сгенерированное для поля автоинкремента - на самом деле это , что говорится в руководстве .

Кроме того, в чем преимущество использования uuid ()? Его вычислительно дорого генерировать, требует много места для хранения, увеличивает стоимость запроса данных и не является криптографически безопасным. Вместо этого используйте генератор последовательности или автоинкремент.

Независимо от того, используете ли вы генератор последовательности или uuid, если вы должны использовать его как единственный уникальный ключ в базе данных, тогда вам сначала нужно будет присвоить значение, прочитать его обратно в phpland и встроить / связать значение как литерал для последующего запроса вставки.

...