前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >案例| +1s导致的故障

案例| +1s导致的故障

作者头像
用户1278550
发布2020-08-21 15:07:01
5210
发布2020-08-21 15:07:01
举报
文章被收录于专栏:idbaidba

该图片由Simon Steinberger在Pixabay上发布

前言

本周有一个业务开发同学要刷数据将 datetime 类型的字段增加1s,但是部分字段的内容变成了 "0000-00-00 00:00:00" 导致相关业务查询数据不一致。具体开发怎么操作的呢?又触发了什么开关导致数据不一致的呢?

问题场景

数据库版本Percona 5.7.22

环境配置

sql_mode: NO_ENGINE_SUBSTITUTION

表结构

代码语言:javascript
复制
 CREATE TABLE `dt` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  `b` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4
复现

更新字段的sql 其实很简单update dt set a=a+1 ,b=b+1 where 条件

代码语言:javascript
复制
test [RW] 11:11:38 >select * from dt;
+-------+---------------------+---------------------+
| id    | a                   | b                   |
+-------+---------------------+---------------------+
| 10031 | 2020-08-20 12:08:50 | 2020-08-20 12:08:59 |
+-------+---------------------+---------------------+
1 row in set (0.00 sec)

test [RW] 11:11:46 >update dt set  a=a+1 ,b=b+1 ;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 1

test [RW] 11:12:09 >show  warnings;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1265 | Data truncated for column 'b' at row 1 |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

 test [RW] 11:12:17 >select * from dt;
+-------+---------------------+---------------------+
| id    | a                   | b                   |
+-------+---------------------+---------------------+
| 10031 | 2020-08-20 12:08:51 | 0000-00-00 00:00:00 |
+-------+---------------------+---------------------+
1 row in set (0.00 sec)

我们可以看到 a字段 "2020-08-20 12:08:50"变成"2020-08-20 12:08:51",时间戳增加1s,符合预期。但是b字段的值从 2020-08-20 12:08:59 变成 0000-00-00 00:00:00,明显不符合预期。这也是导致后面查询某些时间段的数据,导致正常的数据缺失的。

分析

在MySQL 中 对于datetime 和 time类型而言秒级数据的有效值是 0-59,在这个范围内加减都可以,但是结果值超过59秒就会溢出,提示 Data truncated for column 'b'

在严格模式下,针对 59秒直接+1s的时候,直接报错,而不是像 NO_ENGINE_SUBSTITUTION 时给一个warning值。

代码语言:javascript
复制
test [RW] 11:36:15 >show variables like '%sql_mode%';
+---------------+---------------------+
| Variable_name | Value               |
+---------------+---------------------+
| sql_mode      | STRICT_TRANS_TABLES |
+---------------+---------------------+
1 row in set (0.00 sec)
test [RW] 11:36:18 >insert into dt(a,b) values('2020-08-20 12:08:50','2020-08-20 12:08:59');
Query OK, 1 row affected (0.00 sec)

test [RW] 11:36:36 >select * from  dt;
+-------+---------------------+---------------------+
| id    | a                   | b                   |
+-------+---------------------+---------------------+
| 10031 | 2020-08-20 12:08:52 | 0000-00-00 00:00:00 |
| 10032 | 2020-08-20 12:08:50 | 2020-08-20 12:08:59 |
+-------+---------------------+---------------------+
2 rows in set (0.00 sec)

test [RW] 11:36:44 >update  dt set  a=a+1 ,b=b+1  where id=10032;
ERROR 1292 (22007): Incorrect datetime value: '20200820120860' for column 'b' at row 1

正确的方式是什么呢?合理的利用 data_add() 函数。

代码语言:javascript
复制
test [RW] 11:40:47 >update dt set a=date_add(a,interval 1 second),b=date_add(b,interval 1 second) where id=10032;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

 test [RW] 11:41:10 >select * from dt;
+-------+---------------------+---------------------+
| id    | a                   | b                   |
+-------+---------------------+---------------------+
| 10031 | 2020-08-20 12:08:52 | 0000-00-00 00:00:00 |
| 10032 | 2020-08-20 12:08:51 | 2020-08-20 12:09:00 |
+-------+---------------------+---------------------+
2 rows in set (0.00 sec)

总结

我想强调的

datetime 合理的时间段是: '1000-01-01 00:00:00' to '9999-12-31 23:59:59' timestamp 合理的时间段是: '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07'

在开发设计时间字段的时候,不要设置这个两个时间范围之外的值。

MySQL 做逻辑判断或者运算的时候,判断符号,等号左右两边的值务必保持一致。datetime = datetime +1 本身也是不合理的用法。

最后做个小调查吧 你们的生产环境使用了严格模式的 sql_mode

-The End-

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 yangyidba 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 问题场景
    • 复现
    • 分析
    • 总结
    相关产品与服务
    云数据库 SQL Server
    腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档