MySQL中同时存在创建和更新时间戳字段解决方法浅析

明确我的MySQL版本。
mysql> SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.5.29-log |
+------------+
1 row in set (0.00 sec)

现在有这样的需求,一张表中有一个字段created_at记录创建该条记录的时间戳,另一个字段updated_at记录更新该条记录的时间戳。
我们尝试以下几个语句。

第一个,测试通过。

CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

第二个,测试不通过。报ERROR 1293 (HY000)错误。(完整错误信息:ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause)
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

MySQL 5.5.29中有这样的奇葩限制,不明白为什么。既然有这样的限制,那么只有绕道而行,现在尝试给出如下几种解决办法。

第一种,created_at使用DEFAULT CURRENT_TIMESTAMP或者DEFAULT now(),updated_at使用触发器。
具体解决方法如下:
1.temp表结构如下:
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NULL
);

2.插入测试数据:
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('robin',now(),now());
Query OK, 1 row affected (0.03 sec)

mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('wentasy',now(),now());
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 14:00:39 | 2014-09-01 14:00:39 |
| 2 | wentasy | 2014-09-01 14:01:11 | 2014-09-01 14:01:11 |
+----+---------+---------------------+---------------------+
2 rows in set (0.00 sec)

3.在temp上创建触发器,实现更新时记录更新时间;
delimiter |
DROP TRIGGER IF EXISTS tri_temp_updated_at;
CREATE TRIGGER tri_temp_updated_at BEFORE UPDATE ON temp
FOR EACH ROW
BEGIN
SET NEW.updated_at = now();
END;
|
delimiter ;

4.测试。
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 14:00:39 | 2014-09-01 14:03:05 |
| 2 | wentasy | 2014-09-01 14:01:11 | 2014-09-01 14:01:11 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)

第二种,created_at使用触发器,updated_at使用DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP或者DEFAULT now() ON UPDATE now();

具体解决方法如下:
1.temp表结构如下:

CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL,
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

2.在temp上创建触发器,实现插入数据记录创建时间;
delimiter |
DROP TRIGGER IF EXISTS tri_temp_created_at;
CREATE TRIGGER tri_temp_created_at BEFORE INSERT ON temp
FOR EACH ROW
BEGIN
IF new.created_at IS NULL
THEN
SET new.created_at=now();
END IF;
END;
|
delimiter ;

3.插入测试数据:
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('robin',now(),now());
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('wentasy',now(),now());
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 14:08:36 | 2014-09-01 14:08:36 |
| 2 | wentasy | 2014-09-01 14:08:44 | 2014-09-01 14:08:44 |
+----+---------+---------------------+---------------------+
2 rows in set (0.00 sec)

4.测试。
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 14:08:36 | 2014-09-01 14:09:09 |
| 2 | wentasy | 2014-09-01 14:08:44 | 2014-09-01 14:08:44 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)

第三种,created_at指定timestamp DEFAULT '0000-00-00 00:00:00',updated_at指定DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP或者timestamp DEFAULT now() ON UPDATE now();
具体解决方法如下:
1.temp表结构如下:
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT '0000-00-00 00:00:00',
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

2.插入测试数据:
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('robin',now(),now());
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('wentasy',now(),now());
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 14:10:43 | 2014-09-01 14:10:43 |
| 2 | wentasy | 2014-09-01 14:10:57 | 2014-09-01 14:10:57 |
+----+---------+---------------------+---------------------+
2 rows in set (0.00 sec)

3.测试。
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 14:10:43 | 2014-09-01 14:11:24 |
| 2 | wentasy | 2014-09-01 14:10:57 | 2014-09-01 14:10:57 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)

第四种,更换MySQL版本,MySQL 5.6已经去除了此限制。

我们可以看下MySQL 5.5和5.6帮助文档对于这个问题的解释。

From the MySQL 5.5 documentation:

One TIMESTAMP column in a table can have the current timestamp as the default value for initializing the column, as the auto-update value, or both. It is not possible to have the current timestamp be the default value for one column and the auto-update value for another column.

Changes in MySQL 5.6.5:

Previously, at most one TIMESTAMP column per table could be automatically initialized or updated to the current date and time. This restriction has been lifted. Any TIMESTAMP column definition can have any combination of DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses. In addition, these clauses now can be used with DATETIME column definitions. For more information, see Automatic Initialization and Updating for TIMESTAMP and DATETIME.

我们确定下MySQL的版本。

mysql> SELECT VERSION();
+---------------------------------------+
| VERSION() |
+---------------------------------------+
| 5.6.20-enterprise-commercial-advanced |
+---------------------------------------+
1 row in set (0.00 sec)

我们把文首测试不通过的SQL语句在MySQL 5.6下执行,可以看到没有任何错误。
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
Query OK, 0 rows affected (0.28 sec)

接着我们插入测试语句,并作测试。
mysql> INSERT INTO temp(name) VALUES('robin');
Query OK, 1 row affected (0.07 sec)

mysql> INSERT INTO temp(name) VALUES('wentasy');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 15:05:57 | 2014-09-01 15:05:57 |
| 2 | wentasy | 2014-09-01 15:06:02 | 2014-09-01 15:06:02 |
+----+---------+---------------------+---------------------+
2 rows in set (0.01 sec)

mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0

#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 15:05:57 | 2014-09-01 15:06:45 |
| 2 | wentasy | 2014-09-01 15:06:02 | 2014-09-01 15:06:02 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)

总结
本文介绍的方法归根结底,就两条,一是建表语句指定默认值和更新动作,二是使用触发器插入默认值和更新时间。面对当前无法更改的事实,只能采取折中的办法或者牺牲更多来弥补。还有一条值得注意的是,遇到问题多想想不同的解决办法,尽可能地列出所有可能或者可行的方案,这样一来让自己学到更多,二来可以锻炼思维的广度,三来多种方案可以弥补某种方案在特定环境下不可行的不足。

MySQL中同时存在创建和更新时间戳字段解决方法浅析的更多相关文章

  1. MySQL中同一时候存在创建和上次更新时间戳字段解决方法浅析

    在写这篇文章之前.明白我的MySQL版本号. mysql> SELECT VERSION(); +------------+ | VERSION() | +------------+ | 5.5 ...

  2. MySQL中遇到的几种报错及其解决方法

    MySQL中遇到的几种报错及其解决方法 1.[Err] 1064 - You have an error in your SQL syntax; check the manual that corre ...

  3. MySQL there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause同时创建多个更新当前时间戳字段 解决方法

    问题重现 在写这篇文章之前,明确我的MySQL版本,MariaDB 或者你使用 MySQL 8 也会出现如下问题 MySQL 版本 现在有这样的需求,一张表中有一个字段created_at记录创建该条 ...

  4. 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载

    浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...

  5. c++连接mysql并提示“无法解析的外部符号 _mysql_server_init@12”解决方法&提示缺少“libmysql.dll”

    课程作业要用c++连接mysql server,但是出现些小问题,经查阅资料已经解决,做一下笔记. 环境:vs2017, mysql版本是8.0.16-winx64. 设置项目属性   项目 -  C ...

  6. 检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下:

    检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下: 第 一步:首先将msvcr71.dll,  SQLD ...

  7. Android SDK Manager 更新失败的解决方法

    Android SDK Manager 更新失败的解决方法 原文地址 最近使用Android SDK Manager 更新Android SDK tools 发现经常更新失败,获取不到更新信息: Fe ...

  8. log4j中Spring控制台输出Debug级信息过多解决方法

    log4j中Spring控制台输出Debug级信息过多解决方法 >>>>>>>>>>>>>>>>> ...

  9. universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法

    在listview/gridview中使用UIL来display每个item的图片,当图片数量较多需要滑动滚动时会出现卡顿,而且加载过的图片再次上翻后依然会重复加载(显示设置好的加载中图片) 最近在使 ...

随机推荐

  1. Jar命令用法

    JAR文件 JAR文件 全称:Java Archive File , 意思是Java档案文件.通常JAR文件是一种压缩文件,与常见的ZIP压缩文件兼容,通常被称为JAR包. JAR文件和ZIP文件的区 ...

  2. SQL Server插入中文乱码

    如果数据库的Collocation是英文的,字段是varchar类型,向表中插入中文数据,会出现乱码. 解决方法: 方法1. 修改varchar 为 nvarchar类型, 并在插入数据前加N,例如: ...

  3. 搞定vscode编写java

    下载vscode: 地址: https://code.visualstudio.com/ 安装插件 我这里下载的是绿色版,所以解压后 向桌面发送一个快捷方式 找到VS Code 的快捷方式位置: 右键 ...

  4. REST API -- 缓存和并发

    REST API -- 缓存和并发 https://www.cnblogs.com/cgzl/p/9165388.html 本文所需的一些预备知识可以看这里: http://www.cnblogs.c ...

  5. Consul实现服务治理1

    NET Core微服务之基于Consul实现服务治理 https://www.cnblogs.com/edisonchou/p/9148034.html 一.Consul服务注册之配置文件方式 1.1 ...

  6. PT100/PT1000

    热敏电阻:互换性差,非线性严重,测量范围窄-50~300℃. 金属电阻:准备稳定可靠.-200~500℃ PT100:测量范围宽比PT1000宽,分辨率比PT1000低(100倍,即PT1000每变化 ...

  7. C. An impassioned circulation of affection DP

    http://codeforces.com/contest/814/problem/C 12ooyomioomioo21 o2 o 这题我是用dp解的,不过好像很慢,比赛的时候算了下不会mle,就没滚 ...

  8. python实现批量远程执行命令及批量上传下载文件

    #!/usr/bin/env python # -*- coding: utf- -*- # @Time : // : # @Author : xuxuedong # @Site : # @File ...

  9. NPOI导出EXCEL后公式无结果,公式重新计算开关

    但其实这个选项是可以控制的.在NPOI中,这个属性叫做XSSFSheet.ForceFormulaRecalculation. 打开该选项的话,代码为 sheet1.ForceFormulaRecal ...

  10. JAVA基础之File类

    个人理解: File是个文件类,可以用其增加.删除.查找某种类型的文件或者文件夹,同时根据其成员变量的特点可以综合利用,避免出现跨系统的时候出现错误,并且查找时最好输入绝对路径,以免出现不存在的文件. ...