Как получить точный первичный ключ auto_increment вставленной строки? - PullRequest
1 голос
/ 16 января 2020

У меня есть 2 таблицы ниже

create table Order(
   OrderId int primary key auto_increment,
   UserId int not null,
   OrderDate date not null,
   IsPaid boolean default false,
   (...Reference statement for UserId...)
);

create table OrderProduct(
   OrderId int not null,
   ProductName varcahr(1024) not null,
   constraint `fk_orderid_from_orderProduct`
   foreign key (OrderId) references Order(OrderId)
);

Таблица Order представляет каждый заказ, сделанный пользователем, Таблица OrderProduct - это список продуктов, которые содержатся в каждом продукте. Как видите, первичный ключ OrderId для таблицы Order имеет значение auto_increment.

То, что я хочу сделать, выглядит следующим образом:

  1. Создать пустой заказ для пользователя с помощью INSERT INTO Order SET UserId=1234, OrderDate="2019-10-11";
  2. И я могу узнать, какой номер используется в качестве первичного ключа для вставленного Order (присваивается auto_increment), и предположить, что это 2368
  3. Добавить продукт в заказ, как, INSERT INTO OrderProduct (OrderId, ProductName) VALUES (2368, "iPhone"), (2368, "Toy"), (2368, "Computer);

Проблема в том, как получить точную OrderId из таблицы Order, которая автоматически вставляется auto_increment. Это не проблема, если есть только один сеанс, и все запросы обрабатываются последовательно. Но в отношении многих пользователей, создающих свой заказ, это становится проблемой. (В этом случае обрезка вставленного идентификатора ордера по MAX (OrderId) или LastIndex () (верно?) Не всегда точна, поскольку другой пользователь может вставить другой ордер в таблицу (и он увеличится OrderId)

Я решил использовать запрос как (SELECT OrderId WHERE UserId="alex0123" and OrderDate="2019-10-11"), но, как вы знаете, это не тот ответ. Он может обрезать то, что я хочу, но не может быть гарантированно точным, и я думаю, что это неправильно.

Кроме того, я рассматриваю блокировку таблицы при указании c транзакции пользователя. Но это вызовет проблемы с производительностью. (Пока кто-то обрабатывает свой заказ, другой не может этого сделать)

Есть ли способ справиться с этим? Или есть какая-нибудь схема или метод БД, чтобы обойти эту проблему?

Ответы [ 2 ]

2 голосов
/ 16 января 2020

Если оператор SQL вставляет значение для столбца со свойством auto_increment, вставленное значение будет передано клиенту в пакете server OK .

В зависимости от На языке программирования это значение можно получить с помощью функции API, например,

  • C: mysql_insert_id()
  • Python: cursor->lastrowid
  • PHP: mysqli_insert_id()

Но вы можете получить это значение также с помощью одного оператора SQL:

MariaDB [test]> create table mytable (orderid int unsigned not null auto_increment primary key);
Query OK, 0 rows affected (0.03 sec)

MariaDB [test]> insert into mytable values (NULL);
Query OK, 1 row affected (0.02 sec)

MariaDB [test]> select last_insert_id();
+------------------+
| last_insert_id() |
+------------------+
|                1 |
+------------------+
1 row in set (0.00 sec)
1 голос
/ 16 января 2020

Вы можете использовать LAST_INSERT_ID(), поскольку оно поддерживается для каждого клиента (сеанс). Из руководства:

Сгенерированный идентификатор сохраняется на сервере для каждого соединения . Это означает, что значение, возвращаемое функцией данному клиенту, является первым значением AUTO_INCREMENT, сгенерированным для самого последнего оператора, влияющего на столбец AUTO_INCREMENT этим клиентом .

Таким образом, ваш запрос OrderProduct станет:

INSERT INTO OrderProduct (OrderId, ProductName) VALUES 
(LAST_INSERT_ID(), "iPhone"),
(LAST_INSERT_ID(), "Toy"), 
(LAST_INSERT_ID(), "Computer)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...