Windows MySQL v5会引发错误,而Linux和其他版本只会引发警告。这需要修复。 什么鬼?
此外,在MySQL Bugtracker中尝试通过错误#19498进行修复:
Bryce Nesbitt于2008年4月4日下午4:36:
在MS Windows上,“无默认”规则是一个错误,而在其他平台上通常是警告。 虽然不是bug,但如果您在宽松的平台上编写代码,稍后在严格的平台上运行它,则有可能被困住:
个人认为这是一个错误。 搜索“BLOB / TEXT列不能具有默认值”在Google上返回约2,940个结果。 其中大多数是报告在尝试安装在一个系统上工作但在其他系统上无法工作的DB脚本时的不兼容性。
我现在遇到了同样的问题,我正在修改其中一个客户的Web应用程序,最初在Linux MySQL v5.0.83-log上部署。 我运行的是Windows MySQL v5.1.41。 即使尝试使用最新版本的phpMyAdmin提取数据库,它也不会报告有关该文本列的默认值。 但是,当我尝试在Windows上运行插入(在Linux部署上运行良好)时,我会收到ABC列无默认值的错误。 我尝试使用显而易见的默认值(基于该列唯一值的选择),结果收到了如此有用的错误信息 BLOB / TEXT列不能具有默认值。
再次强调,不跨平台地维护基本兼容性是不可接受的,是一个bug。
如何在MySQL 5(Windows)中禁用严格模式:
编辑/my.ini并查找行
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
将其替换为
sql_mode='MYSQL40'
重新启动MySQL服务 (假设服务名称为mysql5)
net stop mysql5
net start mysql5
如果您拥有root/admin权限,您可能能够执行:mysql_query("SET @@global.sql_mode='MYSQL40'");
STRICT_TRANS_TABLES
不是一个好的解决方法,因为我想长期保留它,有很多原因。此外,我遇到了与此相关的兼容性问题。例如,Postgres允许在文本列上设置默认值;这一点让我想迁移到Postgres,而不是从Postgres迁移。 - cazort没有深入了解mySQL引擎,但我认为这听起来像是一种节省内存的策略。我猜想原因在于 文档 中的这段话:
每个BLOB或TEXT值都由一个单独分配的对象在内部表示。这与所有其他数据类型不同,在这些数据类型中,当打开表时,会为每列分配存储空间。
似乎预先填充这些列类型将导致内存使用和性能损失。
作为主要问题:
有人知道为什么不允许这样做吗?
仍未得到回答,我快速搜索并发现一个来自MySQL开发人员的相对较新的补充,位于MySQL Bugs:
[2017年3月17日15:11] Ståle Deraas
由开发人员发布:
这确实是一个有效的功能请求,乍一看,似乎很容易添加。但是,TEXT/BLOBS值未直接存储在用于读取/更新表的记录缓冲区中。因此,为它们分配默认值要更加复杂。
这并不是最终答案,但至少可以作为“为什么”问题的起点。
与此同时,我将编写绕过该问题的代码,要么使列可空,要么在应用程序代码中显式地分配(默认''
)值以供每个insert
使用...
VARCHAR(255)
。但是TINYTEXT
呢?似乎VARCHAR(4096)
也可以使用。 - rubo77支持在MySQL 8.0.13,发布于2018-10-22中将表达式用作默认值,并且适用于TEXT
、JSON
、BLOB
和GEOMETRY
。
仍然不能写成:
create table foo(bar text default 'baz')
但现在你可以写:
create table foo(bar text default ('baz'))
实现相同的事情。
"TEXT/BLOB列中的DEFAULT支持"是MySQL Bugtracker中的一个功能请求(Bug #21532)。
我看到不仅我希望在TEXT列中放置默认值,我认为这个功能应该在MySQL的后续版本中得到支持。
这不能在MySQL 5.0版本中修复,因为显然如果任何人尝试在当前不支持该功能的数据库和任何支持该功能的数据库之间传输数据库,会导致不兼容和数据丢失。
通过使用触发器,您可以获得与默认值相同的效果
create table my_text
(
abc text
);
delimiter //
create trigger mytext_trigger before insert on my_text
for each row
begin
if (NEW.abc is null ) then
set NEW.abc = 'default text';
end if;
end
//
delimiter ;
当然,这个解决方案需要开发人员包装他们的表格创建脚本以补偿在Windows上运行的MySQL问题。您将在转储文件中看到类似的概念。一个非常重要的警告是,如果使用分区,这可能会导致问题。
// Store the current sql_mode
mysql_query("set @orig_mode = @@global.sql_mode");
// Set sql_mode to one that won't trigger errors...
mysql_query('set @@global.sql_mode = "MYSQL40"');
/**
* Do table creations here...
*/
// Change it back to original sql_mode
mysql_query('set @@global.sql_mode = @orig_mode');
针对Ubuntu 16.04:
如何在MySQL 5.7中禁用严格模式:
编辑文件/etc/mysql/mysql.conf.d/mysqld.cnf
如果mysql.cnf中存在以下行:
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
sql_mode='MYSQL40'
sql_mode='MYSQL40'
这个问题已被解决。
sql_mode
设置中的STRICT_TRANS_TABLES
标志。如果在TEXT
数据类型列的INSERT
语句中未指定值,并且标志存在于sql_mode
设置中,则MySQL会报告错误;如果该标志不存在,则MySQL仅报告警告并插入记录。sql_mode
设置中删除STRICT_TRANS_TABLES
。(如果它可能影响数据库上的其他操作,则他可能需要将模式重置为先前的值。)STRICT_TRANS_TABLES
,如果值无效,则MySQL会将其转换为最接近的有效值并插入已调整的值。如果值缺失,则MySQL会插入列数据类型的隐式默认值。在任一情况下,MySQL生成警告而不是错误,并继续处理语句。隐式默认值在第11.6节“数据类型默认值”中有描述。BLOB
、TEXT
、GEOMETRY
和JSON
数据类型不能被赋予默认值。
...TEXT
列不能有默认值,但是如果从sql_mode
中删除STRICT_TRANS_TABLES
,则MySQL在INSERT
语句中为TEXT
列插入空字符串''
,如果没有为TEXT
列指定值。
古老的问题,但解决方案并不太旧:)
遗留原因:
确实是一个有效的功能请求[具有默认的TEXT值],乍一看可能似乎很简单。但是,TEXT/BLOB值不是直接存储在用于读取/更新表的记录缓冲区中的。因此,为它们分配默认值稍微复杂一些。
从MySQL 8.0.13开始,我们可以使用表达式定义默认的TEXT/GEOMETRY/JSON值:
CREATE TABLE product (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name TINYTEXT NOT NULL DEFAULT('<NO-NAME>'),
description TEXT NOT NULL DEFAULT('<NO-DESCRIPTION>'),
caracs JSON NOT NULL DEFAULT(JSON_ARRAY())
);
请注意使用DEFAULT()
而不是简单的经典DEFAULT
。
更多信息请参阅:https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html#data-type-defaults-explicit