我对MySQL中的触发器和唯一约束有一个快速的问题。我会举一个简单的例子。
我有两个表,“帐户”和“用户”。这两个表之间的关系是1(帐户)到很多(用户)。因此,如果您提取具有唯一ID的帐户表,则会遇到该帐户的多个用户。 User表中有一列名为'user_type'。 'user_type'可以是'admin','guest','trial'。 “帐户”必须具有“admin”作为“user_type”的用户。每个帐户只能有1个“管理员”。
那么,有没有办法添加一个唯一约束,以便任何帐户只能有1个'admin'user_type?或者它必须是一个触发器,因为它是MySQL?
谢谢!
答案 0 :(得分:0)
如果您实现了组而不是将其作为用户表的属性,那么您将拥有更灵活的系统。
话虽如此,显然您可以使用触发器强制执行您的业务规则。
但是有一种方法可以使用约束,至少在某种意义上是这样。
创建一个表格:
AccountAdmin
------------
account_admin_id (pk)
account_id (fk) Add unique constraint
user_id (fk)
在account_id上拥有唯一索引后,您可以强制执行规则,即每个帐户只能有一个管理员。
当您创建管理员用户时,您需要在AccountAdmin中插入一行。如果管理员已存在,则约束将阻止您这样做。
话虽如此,为了从一个管理员更改为另一个管理员,您需要先从该表中删除该行,然后添加新行。
一旦开始考虑需要支持像&#34这样的函数的代码类型,请更改admin"或者"推广到管理员,在我看来,触发器更不可取。
关于触发器:
在系统上做了大量工作,要求系统可以扩展到" n"用户,我学会避免的事情之一就是在数据持久性级别上造成瓶颈。 MySQL触发器和存储过程本质上是不可扩展的。
您正在集中数据库中的瓶颈并限制并发性。在没有锁定表格的情况下无法在触发器中执行此练习以确保在您进行查询以确保组织没有管理员时,另一个查询在您执行之前不会插入管理员。它也是一个反模式,必须抛出一个数据库异常并处理它,对于一些根本不是错误的东西(即管理员已经存在)。
如果有一种方法可以将此代码移动到应用程序中(在这种情况下,有),那么这是一种更具伸缩性的解决方案。
答案 1 :(得分:0)
确保每个帐户只有一个管理员用户的最简单方法是将用户行的外键设为管理员。
CREATE TABLE Users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
account_id INT
);
CREATE TABLE Account (
account_id INT AUTO_INCREMENT PRIMARY KEY,
admin_user_id INT NOT NULL
);
ALTER TABLE Account ADD FOREIGN KEY (admin_user_id)
REFERENCES Users (user_id);
ALTER TABLE Users ADD FOREIGN KEY (account_id)
REFERENCES Account(account_id);
INSERT INTO Users () VALUES ();
SET @uid = LAST_INSERT_ID();
INSERT INTO Account (admin_user_id) VALUES (@uid);
UPDATE Users SET account_id = LAST_INSERT_ID() WHERE user_id = @uid;
确保每个帐户的用户仅限于一个管理员,我假设其他类型的多个用户有点棘手。但是使用MySQL 5.7中的虚拟列我们可以做到。
ALTER TABLE Users
ADD COLUMN user_type ENUM('admin', 'guest', 'trial') NOT NULL DEFAULT 'guest',
ADD COLUMN is_admin TINYINT(1) AS (IF(user_type='admin',1,NULL)) STORED,
ADD UNIQUE KEY (account_id, is_admin);
SELECT * FROM Users;
+---------+------------+-----------+----------+
| user_id | account_id | user_type | is_admin |
+---------+------------+-----------+----------+
| 1 | 1 | guest | NULL |
+---------+------------+-----------+----------+
INSERT INTO Users (account_id, user_type) VALUES (1, 'admin');
SELECT * FROM Users;
+---------+------------+-----------+----------+
| user_id | account_id | user_type | is_admin |
+---------+------------+-----------+----------+
| 1 | 1 | guest | NULL |
| 2 | 1 | admin | 1 |
+---------+------------+-----------+----------+
INSERT INTO Users (account_id, user_type) VALUES (1, 'admin');
ERROR 1062 (23000): Duplicate entry '1-1' for key 'account_id'
虚拟列上的UNIQUE KEY忽略NULL。因此,可以存在任意数量的来宾或试用用户,并且它们都在虚拟列中由NULL表示。但是,每个帐户的一个管理员用户可以在该虚拟列中以值1存在。