我有一个带有2个表products
和product_variants
的MySQL数据库。产品具有许多产品变型。这里是一个示例:
products
+----+------+
| id | name |
+----+------+
| 1 | Foo |
| 2 | Bar |
+----+------+
product_variants
+----+-------------+--------+
| id | product_id | value |
+----+-------------+--------+
| 10 | 1 | red |
| 11 | 1 | green |
| 12 | 1 | blue |
| 13 | 2 | red |
| 14 | 2 | yellow |
+----+-------------+--------+
现在,我需要以最有效,最快的方式批量插入许多带有其变体的产品。我有许多产品(100k +)的JSON,如下所示:
[
{
"name": "Foo",
"variants": [{ "value": "red" }, { "value": "green" }, { "value": "blue" }]
},
{
"name": "Bar",
"variants": [{ "value": "red" }, { "value": "yellow" }]
},
...
]
我应该从中生成查询以插入产品。
我的想法是像这样使用insert
查询:
INSERT INTO `products` (name) VALUES ("foo"), ("bar"), ...;
但是我不知道在product_id
的插入查询中要使用什么product_variants
(外键):
INSERT INTO `product_variants` (product_id,value) VALUES (?,"red"), (?,"green"), ...;
(这些交易内的查询)
我曾考虑以手动方式从上一个ID增量指定产品ID,但是当并发连接同时插入产品或同时运行2个或多个批量插入过程时,会出现错误。
我可以使用什么策略来实现自己的目标?有没有标准的方法可以做到这一点?
ps:如果可能,我不想更改2个表的结构。
您可以使用last_insert_id()
从最后一条语句中获取最后生成的ID。但是,如上所述,由于这仅获得语句的最后一个ID,因此要求您分别处理每个产品。您可以批量插入变体。但是从给定JSON的结构来看,我认为这使得遍历该JSON变得更加容易。应将每个产品及其变体插入事务中,以便如果由于某种原因导致产品表中的INSERT
失败,则不会将产品的变体添加到先前的产品中。
START TRANSACTION;
INSERT INTO products
(name)
VALUES ('Foo');
INSERT INTO product_variants
(product_id,
value)
VALUES (last_insert_id(),
'red'),
(last_insert_id(),
'green'),
(last_insert_id(),
'blue');
COMMIT;
START TRANSACTION;
INSERT INTO products
(name)
VALUES ('Bar');
INSERT INTO product_variants
(product_id,
value)
VALUES (last_insert_id(),
'red'),
(last_insert_id(),
'yellow');
COMMIT;
如果您已经在表中包含JSON,则可以使用两个语句来完成(非常有效):
INSERT INTO Products (name)
SELECT name
FROM origial_table; -- to get the product names
INSERT INTO Variants (product_id, `value`)
SELECT ( SELECT id FROM Products WHERE name = ot.name ),
`value`
FROM origial_table AS ot;
实际上,name
和value
需要适合作为JSON表达式以提取值。