首页 > 解决方案 > MySQL 5.7 准备好的语句更新了错误的时间戳列

问题描述

当与准备好的语句一起使用时,我在更新表时遇到了一些问题。似乎 mysql 正在更新一个错误的列,该列甚至没有在更新命令中指定。

准备:

drop table test1;
create table test1(
  id int not null,
  show_from timestamp not null,
  updated_at timestamp NULL DEFAULT NULL
);
insert into test1(id, show_from, updated_at) values(1, '2018-01-11 12:10:11.19808', '2019-04-15 11:50:00.704748');

在一批中执行此操作:

UPDATE test1 SET show_from='2018-04-15 11:50:00.704748' WHERE id=1;
SELECT * FROM test1;

返回:

1    2018-04-15 13:50:01    2019-04-15 13:50:01

正如预期的那样。

现在在一批中执行此操作:

PREPARE stmt1 FROM 'UPDATE test1 SET updated_at=? WHERE id=?';
SET @s1='2019-02-11 12:12:11.19808';
SET @s2=1;
EXECUTE stmt1 USING @s1, @s2;
DEALLOCATE PREPARE stmt1;
SELECT * FROM test1;

返回:

1    2019-04-15 12:54:27    2019-02-11 13:12:11

为什么 mysql 更新 show_from 列?

标签: mysqlsqltimestampsql-updateprepared-statement

解决方案


该列被声明为时间戳,而不是 null

show_from timestamp not null

在这种模式下,MySQL 将在每次更新行(它的任何列)时更新列。从手册

如果explicit_defaults_for_timestamp系统变量被禁用,则第一TIMESTAMP列两者都有DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP如果两者都没有明确指定。

该文档提出了一些解决方法,例如:

  • 使用指定常量默认值的 DEFAULT 子句定义列。

  • 指定 NULL 属性。这也会导致列允许 NULL 值,这意味着您不能通过将列设置为 NULL 来分配当前时间戳。

我实际上会推荐这个:

  • 启用explicit_defaults_for_timestamp系统变量。

推荐阅读