处理 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 不允许。有什么方法可以通过索引甚至存储过程来实现吗?

类似问题(供参考):

  1. conditional unique constraint
  2. SQL can I have a "conditionally unique" constraint on a table?
  3. https://dba.stackexchange.com/questions/7443/function-based-index-as-a-conditional-unique-key
  4. Can I conditionally enforce a uniqueness constraint?
  5. 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

中几乎相同