为什么要在所需的数据库列上设置"null:false,默认值:" ""?



我正在使用Devise构建一个用于身份验证的Rails应用程序,其默认数据库迁移设置了以下列:

## Database authenticatable
t.string :email,              null: false, default: ""
t.string :encrypted_password, null: false, default: ""

同时设置null: falsedefault: ""的目的是什么?

我的理解是,null: false有效地使值成为必需的:即,尝试在该列中保存具有NULL值的记录将在数据库级别失败,而不依赖于对模型的任何验证。

但是default: ""基本上通过在保存之前简单地将NULL值转换为空字符串来撤消它。

我知道对于可选列,您希望拒绝NULL值,以确保该列中的所有数据都属于同一类型。但是,在这种情况下,电子邮件和密码绝对不是用户身份验证模型上的可选属性。我确信模型中有验证以确保您无法创建具有空电子邮件地址的用户,但是为什么要首先在此处设置default: ""它是否有一些好处或防止一些我没有考虑过的边缘情况?

广义地说:

  • 要使列成为必填列,必须对其设置null: false。无论是创建新表还是更新现有表,都是如此。
  • 如果您要更新现有表,数据库引擎将尝试在每行中使用NULL填充该新列。在这种情况下,必须使用default: ""覆盖此行为,否则它将与null: false冲突,迁移将失败。

关于设计:

Devise 使用两个单独的模板来构建迁移:migration.rb用于创建新表,migration_existing.rb用于更新现有表(请参阅 GitHub 上的源代码)。两个模板都调用相同的migration_data方法来生成有问题的行(即指定null: false, default: ""的行),但如上所述,default: ""仅在后一种情况下才真正相关(有关更多信息,请参阅 O. Jones 的回答)。

因此,对您的问题的简短回答,特别是在 Devise 迁移的情况下,是"因为生成器使用借用的代码并不总是适用,但仍然不会破坏任何东西。

UNIQUE列的注意事项:

请注意,在大多数流行的 SQL 引擎中,唯一索引列仍然可以包含多行NULL值,只要它们不是必需的(自然)。但是使新列既是必需的又唯一的(null: falsedefault: ""unique: true)的效果是无法添加它:数据库引擎尝试在每行中用空字符串填充新列,这与unique约束冲突并导致迁移失败。

(此机制失败的唯一情况是,如果表中只有一行 — 它为新列获取一个空白字符串值,该值自然会传递唯一性约束,因为它是唯一的记录。

因此,另一种看待它的方式可能是,这些选项是一种安全机制,可防止您运行不应运行的迁移(即,追溯性地将所需列添加到已填充的表中)。

插入类型有所不同。例如,假设您有一个new_table表,如下所示:

CREATE TABLE IF NOT EXISTS `new_table` (
`col1` VARCHAR(10) NOT NULL,
`col2` VARCHAR(10) NOT NULL DEFAULT '',
`col3` VARCHAR(10) NULL DEFAULT '');

当您使用显式插入NULL时,您将获得NULL

INSERT INTO new_table(col1,col2,col3) VALUES('a','b',NULL);
'a','b',NULL

相同的技巧col2将导致错误:

INSERT INTO new_table(col1,col2,col3) VALUES('a',NULL,'c');

但是当你使用隐式插入NULL时,你会得到默认值:

INSERT INTO new_table(col1,col2) VALUES('a','b');
'a','b',''

的意思是,设置默认值不会阻止NULL对此列的断言,而是仅在未显式给出值时使用。

某些应用程序软件对 NULL 值进行清理,但在零长度文本字符串上不这样做。在Oracle中,它们是一回事,但在MySQL中不是。

更改表以添加列时,事情变得有趣。在这种情况下,默认值是必需的,因此 DBMS 可以填充新列。

我认为这是因为MySQL的"严格模式"不允许您在不提供默认值的情况下禁止空值。

来自 mysql 文档: https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html

对于没有显式DEFAULT子句的NOT NULL列中的数据输入,如果INSERT或PLACE语句不包含该列的值,或者UPDATE语句将该列设置为NULL,则MySQL根据当时有效的SQL模式处理该列:如果启用了严格SQL模式,则事务表会发生错误,并且该语句将回滚。对于非事务表,会发生错误,但如果多行语句的第二行或后续行发生此错误,则会插入前面的行。如果未启用严格模式,MySQL会将列设置为列数据类型的隐式默认值。

相关内容

  • 没有找到相关文章

最新更新