处理 MYSQL table 中的并行相同插入
Handle parallel identical insertion in MYSQL table
我们正在开发一个 Spring 由 MySQL 数据库支持的启动应用程序,我有一个问题找不到答案,尽管这里有几个类似的问题。
问题是如果有多个 并行相同的插入 语句 运行.
,则只在数据库中保留一个插入
例如,如果我的实体具有属性 (Id, parent_id and status)
,我们不想允许多个具有 same parent_id and status = 1
的实体 - 即使它们以这种形式来自客户端,它用相同的请求向我们的端点发送垃圾邮件。我知道其他数据库供应商允许使用称为 条件 唯一键的东西,即像 (parent_id, status = 1)
这样的唯一键,但 MySql 不允许。有什么方法可以通过索引甚至存储过程来实现吗?
类似问题(供参考):
- conditional unique constraint
- SQL can I have a "conditionally unique" constraint on a table?
- https://dba.stackexchange.com/questions/7443/function-based-index-as-a-conditional-unique-key
- Can I conditionally enforce a uniqueness constraint?
- https://dba.stackexchange.com/questions/43/how-to-create-a-conditional-index-in-mysql
你可以通过一些小技巧来做到。
包含一个带有 IF() 函数的虚拟持久列。
如果 status = 1 else NULL,这将存储 parent_id
所以你可以在这个字段上创建一个 UNIQUE KEY
CREATE TABLE `cond` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`status` int(11) DEFAULT NULL,
`cond_status` int(11) GENERATED ALWAYS AS (if(`status` = 1,`parent_id`,NULL)) STORED,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_cond_status` (`cond_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
样本
MariaDB [Bernd]> select * from cond;
Empty set (0.10 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1234, 0);
Query OK, 1 row affected (0.05 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 0);
Query OK, 1 row affected (0.01 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 2);
Query OK, 1 row affected (0.00 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 2);
Query OK, 1 row affected (0.02 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 1);
Query OK, 1 row affected (0.22 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 4);
Query OK, 1 row affected (0.01 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 1);
ERROR 1062 (23000): Duplicate entry '1235' for key 'idx_cond_status'
MariaDB [Bernd]>
MariaDB [Bernd]> select * from cond;
+----+-----------+--------+-------------+
| id | parent_id | status | cond_status |
+----+-----------+--------+-------------+
| 1 | 1234 | 0 | NULL |
| 2 | 1235 | 0 | NULL |
| 3 | 1235 | 2 | NULL |
| 4 | 1235 | 2 | NULL |
| 5 | 1235 | 1 | 1235 |
| 6 | 1235 | 4 | NULL |
+----+-----------+--------+-------------+
6 rows in set (0.08 sec)
MariaDB [Bernd]>
注意:创建 table 适用于 MariaDB,但在 MySQL
中几乎相同
我们正在开发一个 Spring 由 MySQL 数据库支持的启动应用程序,我有一个问题找不到答案,尽管这里有几个类似的问题。 问题是如果有多个 并行相同的插入 语句 运行.
,则只在数据库中保留一个插入例如,如果我的实体具有属性 (Id, parent_id and status)
,我们不想允许多个具有 same parent_id and status = 1
的实体 - 即使它们以这种形式来自客户端,它用相同的请求向我们的端点发送垃圾邮件。我知道其他数据库供应商允许使用称为 条件 唯一键的东西,即像 (parent_id, status = 1)
这样的唯一键,但 MySql 不允许。有什么方法可以通过索引甚至存储过程来实现吗?
类似问题(供参考):
- conditional unique constraint
- SQL can I have a "conditionally unique" constraint on a table?
- https://dba.stackexchange.com/questions/7443/function-based-index-as-a-conditional-unique-key
- Can I conditionally enforce a uniqueness constraint?
- https://dba.stackexchange.com/questions/43/how-to-create-a-conditional-index-in-mysql
你可以通过一些小技巧来做到。
包含一个带有 IF() 函数的虚拟持久列。 如果 status = 1 else NULL,这将存储 parent_id 所以你可以在这个字段上创建一个 UNIQUE KEY
CREATE TABLE `cond` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`status` int(11) DEFAULT NULL,
`cond_status` int(11) GENERATED ALWAYS AS (if(`status` = 1,`parent_id`,NULL)) STORED,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_cond_status` (`cond_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
样本
MariaDB [Bernd]> select * from cond;
Empty set (0.10 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1234, 0);
Query OK, 1 row affected (0.05 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 0);
Query OK, 1 row affected (0.01 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 2);
Query OK, 1 row affected (0.00 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 2);
Query OK, 1 row affected (0.02 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 1);
Query OK, 1 row affected (0.22 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 4);
Query OK, 1 row affected (0.01 sec)
MariaDB [Bernd]> INSERT INTO cond (parent_id,`status`) VALUES(1235, 1);
ERROR 1062 (23000): Duplicate entry '1235' for key 'idx_cond_status'
MariaDB [Bernd]>
MariaDB [Bernd]> select * from cond;
+----+-----------+--------+-------------+
| id | parent_id | status | cond_status |
+----+-----------+--------+-------------+
| 1 | 1234 | 0 | NULL |
| 2 | 1235 | 0 | NULL |
| 3 | 1235 | 2 | NULL |
| 4 | 1235 | 2 | NULL |
| 5 | 1235 | 1 | 1235 |
| 6 | 1235 | 4 | NULL |
+----+-----------+--------+-------------+
6 rows in set (0.08 sec)
MariaDB [Bernd]>
注意:创建 table 适用于 MariaDB,但在 MySQL
中几乎相同