1.8.3.3 无效数据的约束

MySQL 5.7.5 和更高版本默认情况下使用严格的 SQL 模式,该模式会处理无效值,以便服务器拒绝它们并中止出现它们的语句(请参见第 5.1.10 节“服务器 SQL 模式”)。以前,MySQL 更原谅数据 Importing 中使用的错误值。现在,这要求禁用严格模式,不建议这样做。本节的其余部分讨论禁用严格模式时 MySQL 遵循的旧行为。

如果您不使用严格模式,则每当您在列中插入“不正确”值(例如在NULL插入NOT NULL列或在数值列中插入太大的数值)时,MySQL 都会将该列设置为“最佳”值”,而不产生错误:以下规则更详细地描述了它的工作方式:

  • 如果尝试将超出范围的值存储到数字列中,则 MySQL Server 会存储零,最小可能值或最大可能值,以最接近无效值的那个为准。

  • 对于字符串,MySQL 存储空字符串或该列中可以存储的尽可能多的字符串。

  • 如果您尝试将不以数字开头的字符串存储到数字列中,则 MySQL Server 将存储 0.

  • 第 1.8.3.4 节“ ENUM 和 SET 约束”中所述处理ENUMSET列的无效值。

  • MySQL 允许您将某些不正确的日期值存储到DATEDATETIME列中(例如'2000-02-31''2000-02-00')。在这种情况下,如果应用程序未启用严格的 SQL 模式,则由应用程序来验证日期,然后再存储它们。如果 MySQL 可以存储日期值并检索完全相同的值,则 MySQL 按给定的方式存储它。如果日期完全错误(服务器无法存储),则将特殊的“零”日期值'0000-00-00'存储在该列中。

  • 如果您尝试将NULL存储到不包含NULL值的列中,则单行INSERT语句会发生错误。对于多行INSERT语句或插入...选择语句,MySQL Server 存储列数据类型的隐式默认值。通常,对于数字类型为0,对于字符串类型为空字符串(''),对于日期和时间类型为“零”值。隐式默认值在第 11.6 节“数据类型默认值”中讨论。

  • 如果INSERT语句没有为列指定任何值,则当列定义包含显式的DEFAULT子句时,MySQL 将插入其默认值。如果定义中没有这样的DEFAULT子句,则 MySQL 将为列数据类型插入隐式默认值。

在严格模式无效时使用上述规则的原因是,在语句开始执行之前,我们无法检查这些条件。如果在更新几行后遇到问题,我们将无法回滚,因为存储引擎可能不支持回滚。终止声明的选择不是那么好。在这种情况下,更新将“完成一半”,这可能是最糟糕的情况。在这种情况下,最好“尽力而为”,然后 continue 进行,好像什么也没发生一样。

您可以使用STRICT_TRANS_TABLESSTRICT_ALL_TABLES SQL 模式选择对 Importing 值的更严格处理:

SET sql_mode = 'STRICT_TRANS_TABLES';
SET sql_mode = 'STRICT_ALL_TABLES';

STRICT_TRANS_TABLES为事务性存储引擎以及非事务性引擎启用严格模式。它是这样的:

  • 对于事务存储引擎,语句中任何地方出现的错误数据值都会导致该语句中止并回滚。

  • 对于非事务性存储引擎,如果要插入或更新的第一行中发生错误,则语句中止。 (当错误发生在第一行时,可以像处理事务 table 一样中止该语句,以使该 table 保持不变.)第一行之后的行中的错误不会中止该语句,因为该 table 已经被 table 更改了。第一排。相反,错误的数据值会被调整并导致警告而不是错误。换句话说,如果使用STRICT_TRANS_TABLES,则错误的值将导致 MySQL 回滚到目前为止已完成的所有更新,如果可以这样做,而无需更改 table。但是一旦更改了 table 格,其他错误将导致调整和警告。

要进行更严格的检查,请启用STRICT_ALL_TABLES。这与STRICT_TRANS_TABLES相同,除了对于非事务性存储引擎而言,即使在第一行之后的行中出现错误数据,错误也会中止该语句。这意味着,如果在非事务 table 的多行插入或更新过程中发生错误,则会导致部分更新。较早的行将被插入或更新,但是从错误的角度来看则不会。为了避免在非事务 table 中出现这种情况,请使用单行语句,或者如果可以接受转换警告而不是错误,则使用STRICT_TRANS_TABLES。首先要避免出现问题,请勿使用 MySQL 检查列内容。让应用程序确保仅将有效值传递给数据库是最安全的(而且通常更快)。

使用任一严格模式选项,通过使用INSERT IGNOREUPDATE IGNORE而不是INSERTUPDATE不带IGNORE,可以将错误视为警告。