MariaDB 10.0,innodb:有条件的唯一约束?

时间:2014-08-27 00:04:37

标签: mysql ruby-on-rails locking unique-constraint mariadb

我的架构,简化:

人: id(int),name(string),allow_duplicate_name(int)

allow_duplicate_name为1表示true,0表示false。

我想阻止插入新记录,如果它们的名称字段是非唯一的,但只有当它们有allow_duplicate_name == 1.所以如果我们有下表:

id  name  allow_duplicate_name
1   jack  1
2   jack  1
3   ryan  1
4   jack  1

然后以下陈述应该成功:

INSERT INTO people (name, allow_duplicate_name)
VALUES ('jack', 1);

但这句话应该失败:

INSERT INTO people (name, allow_duplicate_name)
VALUES ('jack', 0);

我的根本问题是我有一个竞争条件,其中两个并发事务都检查是否存在重复,看到它没有,然后插入一个具有相同名称和allow_duplicate_name = 0的新记录。

我的另一个想法是在检查是否在提交每个事务之前添加重复项时使用READ UNCOMMITTED,而是将其回滚,让应用程序采取不同的操作(例如,选择一个新名称),因为我们可以容忍(它会比理想情况低得多,但我们可以处理它......)每个事务看到另一个事务然后自动回滚的竞争条件,但我们绝对不能允许插入/更新设置重复name_with allow_duplicate_name = 0。

我听说我们的设置使得存储过程非常难以使用,但是存储过程可能是解决此问题的唯一有效方法吗?

1 个答案:

答案 0 :(得分:0)

你几乎可以做你想做的事。但是您想要更改变量的名称。关键的想法是,唯一索引允许重复NULL个值。所以,当" allow_duplicate_name"是NULL,那么你可以得到重复。

我建议将字段重命名为DuplicatesNotAllowed。然后创建索引:

 create unique index idx_people_name_duplicatesnotallowed on people(name, duplciatesnotallowed);

您可以将值插入:

INSERT INTO people (name, duplciatesnotallowed)
    VALUES ('jack', NULL);

这将成功。

INSERT INTO people (name, allow_duplicate_name)
    VALUES ('jack', 1);

这将使第二时间运行失败。但是,如果更新现有行的字段,则会失败。我不确定这是否符合您的需求。