为什么要在所需的数据库列上设置`null:false,default:“”`?

时间:2017-07-04 11:08:07

标签: mysql validation devise null relational-database

我正在使用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: ""它有什么好处或者防止我没有考虑过的一些边缘案例?

4 个答案:

答案 0 :(得分:3)

从广义上讲:

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

关于Devise:

Devise使用两个单独的模板来构建迁移:migration.rb用于创建新表,migration_existing.rb用于更新现有表(请参阅source on GitHub)。两个模板都调用相同的migration_data method来生成有问题的行(即,指定null: false, default: ""的行),但如上所述,default: ""只是真的与后一种情况相关(更多见O. Jones’ answer)。

所以对你的问题的简短回答,特别是在Devise迁移的情况下,是“因为生成器使用的借用代码并不总是适用,但仍然没有破坏任何东西。”

UNIQUE列的考虑因素:

请注意,在大多数流行的SQL引擎uniquely indexed columns can still contain multiple rows of NULL values中,只要它们不是必需的(自然)。但是,创建新列的效果是唯一 null: falsedefault: ""和{ {1}})无法添加:数据库引擎尝试使用每行中的空字符串填充新列,这与unique: true约束冲突并导致迁移失败。

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

另一种看待它的方法可能是这些选项是一种安全机制,阻止您运行不应该运行的迁移(追溯性地将已填充的表添加到已填充的表中)

答案 1 :(得分:1)

某些应用程序软件会对NULL值进行gack,但不会对零长度文本字符串进行gack。在Oracle中,它们是相同的,但不是在MySQL中。

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

答案 2 :(得分:0)

插入类型有所不同。例如,假设您有一个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断言到此列,而只会在未明确指定值时使用。

答案 3 :(得分:0)

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

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

<块引用>

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