例子:
以下是员工表:
CREATE TABLE `employees` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`code` varchar(4) NOT NULL,
`deleted_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
);
这个 code
是一个4个字符的简单登录代码。软删除是使用 deleted_at
现场。现在的员工是那些 deleted_at=NULL
.
我们需要在现有员工之间保持代码的唯一性。
使用唯一的约束 code
字段将阻止当前员工使用已被软删除员工使用的代码。
如何强制执行此约束?
这是如何在mysql中实施一致性约束的一般问题的一个例子。
编辑:
正如@bill karwin所建议的那样,可以更改模式以使用唯一的约束。
如何应用可能跨越多个表的复杂一致性约束?
一种方法(如果可能)是更改模式,以便使用外键约束或唯一约束应用约束。
有没有其他方法可以应用复杂的一致性约束?
2条答案
按热度按时间kuhbmx9i1#
一种解决方案是创建一个可为null的列
is_active
限制为null或单个非null值的。列code
以及is_active
一起一定是独一无二的。如果
is_active
为空,则它允许在code
列。如果is_active
如果不为null,则只允许一个值“yes”,因此code
列必须唯一。deleted_at
不再指示员工当前是否处于活动状态,仅当该员工处于非活动状态时。请回复您的意见:
跨多个表的约束称为
ASSERTIONS
在sql标准中,但实际上没有rdbms产品实现该标准中的特性。有些使用触发器来实现约束,但是如何设计触发器来高效地执行您想要的操作并不总是显而易见的。
老实说,大多数人都求助于应用程序逻辑来解决这些约束。这会带来一些比赛条件的风险。一旦执行select语句来验证数据是否满足约束,其他一些并发会话可能会在会话提交更改之前提交破坏约束的数据。
唯一的解决方案是使用悲观锁定,以确保没有其他会话可以跳到您前面。
vaqhlq812#
一个相对简单的解决方法是改变
deleted_at
列默认为NULL
(例如“1900-01-01”,或者如果启用了“0”日期“0000-00-00”)。然后可以创建UNIQUE
索引打开(code, deleted_at)
这将阻止任何员工使用当前员工拥有的代码(因为您可以在(code,default)
),但不排除使用前一个员工使用过的代码,因为默认值与deleted_at
时间戳。