在MySQL数据库中添加约束以确保唯一性

时间:2018-07-03 09:07:36

标签: mysql sql database

我的SQL表具有以下DDL

CREATE TABLE `new_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `family_id` int(11) NOT NULL,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
  ) 

我想在这个简单的表格中保存姓氏。为此,我有一个微服务,调用方通过JSON发送家庭详细信息:

{
  "family_id" : 1,
  "names": ["name1", "name2"]
}

该ID是通过MySQL的自动递增生成的。

因此上述JSON将最终触发两个插入语句:

  • 插入(family_id,name)值(1,name1)
  • 插入(family_id,name)值(1,name2)

当新请求带有表中存在的family_id时,就会出现问题。这不应该被允许,我正在做一个查询以便搜索family_id是否存在。如果存在,则会引发异常。如何避免此查询?如果需要,可以更改表架构。如果可以添加诸如“请求ID”之类的内容,或为每个请求建立唯一性的向导,是否可以?

所有数据应在同一表上。

下面是带有一些数据的表格示例

enter image description here

(来自注释)我无法创建第二张表。一切都应该放在一张桌子上。

4 个答案:

答案 0 :(得分:6)

您应该规范化架构并使用两个表。

家庭和(我假设)人。然后,您可以为UNIQUE使用family_id约束,并将family_id作为外键添加到Person表中。

答案 1 :(得分:3)

您需要两个表。

CREATE TABLE Families (
    family_id MEDIUMINT UNSIGNED  AUTO_INCREMENT,
    ...
    PRIMARY KEY(family_id)
    );

CREATE TABLE FamilyNames (
    family_id MEDIUMINT UNSIGNED,   -- not auto-inc here
    name VARCHAR(66) NOT NULL,
    ...
    PRIMARY KEY(family_id, name)    -- note "composite"
    );

PRIMARY KEYUNIQUE KEYKEY

您说您不能添加第二张表。但为什么?您提到需要生成特定的JSON吗?如果必要的话,不能简单地通过两个表中的JOIN完成吗?

答案 2 :(得分:2)

如果您不能创建第二个表来正确地对约束进行建模,那么您将不得不求助于序列化插入:

  1. LOCK TABLES new_table WRITE;
  2. 使用SELECT检查表中是否存在家庭ID。
  3. 如果不提供家庭ID,请INSERT您的新数据。
  4. UNLOCK TABLES;

必须锁定表,因为否则您将出现竞争状况。两个会话可以检查家族ID是否存在,都发现它不存在,然后都以其INSERT进行。如果您锁定表,则一个会话将获取该锁并执行其工作,而另一会话必须等待该锁,并且在获取该锁时,其检查将发现该家族ID已被插入。第一次会议。

通常认为这种方法不利于并发,如果有很多请求,这可能会限制吞吐量。但是,如果您的请求很少,那么对吞吐量的影响将很小。

答案 3 :(得分:0)

这是解决设计问题的方法,但我认为我不妨发布它。您可以生成如下查询:

INSERT INTO `new_table` (`family_id`, `name`)
SELECT * FROM (
    SELECT 1, 'name1'
    UNION ALL
    SELECT 1, 'name2'
) x
LEFT JOIN `new_table` n ON n.family_id = 1
WHERE n.family_id IS NULL

然后检查受影响的行数,以确定是否成功。