MySQL允许您同时使用支持回滚的事务表和不支持回滚的非事务表。因此,MySQL中的约束处理与其他数据库管理系统有所不同。当在非事务表中插入或更新了大量行时,并且在发生错误时无法回滚更改时,我们必须处理这种情况。
基本理念是,MySQL服务器在解析要执行的语句时会尽可能地检测出错误,并在执行语句时尝试恢复任何发生的错误。我们在大多数情况下都是如此处理的,但并不是所有情况下都可以做到。
当错误发生时,MySQL有两个选项:停止语句的执行或尽可能地从问题中进行恢复并继续执行。默认情况下,服务器会选择后者。这意味着,例如,服务器可能会将无效的值强制转换为最接近的有效值。
有多种SQL模式选项可用于更精确地控制如何处理错误数据值,以及在错误发生时是继续语句执行还是中止。通过使用这些选项,您可以配置MySQL服务器以更接近其他拒绝不当输入的DBMS的传统方式工作。SQL模式可以在服务器启动时全局设置,以影响所有客户端。各个客户端可以在运行时设置SQL模式,使每个客户端能够选择最适合其需求的行为。
以下几节将介绍MySQL Server如何处理不同类型的约束。
通常,对于可能违反主键约束、唯一键约束或外键约束的数据更改语句(如INSERT或UPDATE),会发生错误。如果您使用的是诸如InnoDB之类的事务性存储引擎,MySQL会自动回滚该语句。如果您使用的是非事务性存储引擎,MySQL会在出现错误的行处停止处理该语句,并保留其他未处理的行。
MySQL支持INSERT、UPDATE等语句中的IGNORE关键字。如果使用该关键字,在发生主键或唯一键冲突时,MySQL会忽略该错误,并继续处理下一行数据。
您可以借助mysql_info() C API函数来获取实际插入或更新的行数信息。您还可以使用SHOW WARNINGS语句来查看警告信息。
InnoDB和NDB表支持外键约束。
外键允许您在表之间进行相关数据的交叉引用,而外键约束有助于保持这些分散的数据的一致性。
MySQL在CREATE TABLE和ALTER TABLE语句中支持ON UPDATE和ON DELETE外键引用。可用的参照动作包括RESTRICT、CASCADE、SET NULL和NO ACTION(默认选项)。
MySQL Server支持SET DEFAULT,但在InnoDB中目前被拒绝为无效。由于MySQL不支持延迟约束检查,因此NO ACTION被视为RESTRICT。
允许使用MATCH FULL、MATCH PARTIAL和MATCH SIMPLE,但应尽量避免使用,因为它们会导致MySQL Server忽略同一语句中使用的任何ON DELETE或ON UPDATE子句。在MySQL中,MATCH选项没有其他影响,实际上全时强制执行MATCH SIMPLE语义。
MySQL要求对外键列进行索引;如果您创建一个具有外键约束但在某列上没有索引的表,将会自动创建索引。
您可以从Information Schema KEY_COLUMN_USAGE表中获取有关外键的信息。下面是一个针对该表的查询示例:
mysql> SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME
> FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
> WHERE REFERENCED_TABLE_SCHEMA IS NOT NULL;
+--------------+---------------+-------------+-----------------+
| TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME | CONSTRAINT_NAME |
+--------------+---------------+-------------+-----------------+
| fk1 | myuser | myuser_id | f |
| fk1 | product_order | customer_id | f2 |
| fk1 | product_order | product_id | f1 |
+--------------+---------------+-------------+-----------------+
3 rows in set (0.01 sec)
有关InnoDB表上的外键信息也可以在INFORMATION_SCHEMA数据库的INNODB_FOREIGN和INNODB_FOREIGN_COLS表中找到。
InnoDB和NDB表支持外键。
默认情况下,MySQL 8.0会拒绝无效或不正确的数据值,并中止出现问题的语句。可以改变这种行为,使其更宽容地处理无效值,即服务器将其强制转换为有效值进行数据输入,方法是禁用严格的SQL模式,但这不被推荐。
旧版本的MySQL默认采用宽容的行为。
ENUM和SET列提供了一种有效的方式来定义只能包含给定值集合的列。
除非禁用了严格模式,否则ENUM或SET列的定义将作为对输入到该列的值的约束。不满足这些条件的值会导致错误的发生:
如果在严格模式下使用INSERT IGNORE或UPDATE IGNORE,可以抑制无效值的报错。在这种情况下,将生成一个警告而不是错误。对于ENUM,值会以错误成员(0)的形式插入。对于SET,值会按照给定的值插入,但会删除任何无效的子字符串。例如,'a,x,b,y' 的结果是 'a,b'。