Contents
  1. 1. 前言
  2. 2. 发现问题
  3. 3. 数据修复
  4. 4. 关于on update
  5. 5. 总结
  6. 6. Reference

前言

两周前接了个活儿,甲方的公众号需要做一个前端记录用户信息,管理端查看用户填写的信息并且审批的项目。
甲方提供短信平台接口,公众号获取openid的转接接口,FTP服务器,数据库。
项目制作也没有多难,本地测通以后,把项目放到我自己的服务器里模拟了一下,都通了才放到甲方的FTP里。
原本投产时间是周一,但是周四甲方临时要求放到周五投产,这样他们周末出去推广的人就能用了。
因为我已经做完了,和甲方的技术联调也都完成了,于是周五下午给他上掉。

发现问题

周末出差,周日晚上才到家。
看了一下数据库,发现问题,信息表创建时间都是0时几分几秒,而手机绑定时间都是8时同分同秒。
甲方给的数据库默认时间是UTC,但是代码里只有创建数据的时候才会给创建时间设值。
SHOW VARIABLES LIKE '%time_zone%';

Variable name Value
system_time_zone Coordinated Universal Time
time_zone SYSTEM

仔细撸了一遍代码并没有发现问题,将生产环境的代码和本地对比了一下也无差异。接着在本地和自己的服务器里(修改了mysql的配置文件,将时区也设为UTC)又赶紧测了一次也没有出现问题。

正感觉一筹莫展的时候,用sqlyogSchema Synchronization Tool对比了一下生产与本地的数据库发现问题了。

1
2
3
USE `db_xxyy`;
ALTER TABLE `some_info_table`
CHANGE `create_time` `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP COMMENT '创建时间' after `status`;

此时生产环境数据库内的表结构是类似这样的。

在本地模拟了一下,确定了是on update的问题,赶紧先把生产环境的on update去掉,之后的数据创建时间都正常了。

数据修复

接着找办法修复那些错误的创建时间。
好在有之前做项目中学到的防止扯皮好习惯,在建表的时候多建了一张some_data_log表,用来记录数据的增删改操作。其中就有进行操作的时间,可以用对表名为some_info_table的表进行insert操作时的操作时间来作为some_info_table中数据的创建时间。
虽然data_loginfo_table并没有什么字段可以关联,也就是说普通的update join并不可行。但是错误的创建时间数据条数是能够在data_log表中找到对应数据的。
于是搞了一张中间表,将info_table的涉及id按顺序插入列1,将data_log的create_time按时间排序插入列2。
使用中间表和info_table进行update join操作成功将数据修复了。

关于on update

按照mysql的官方手册里的说明,on update是数据类型为timestamp的一个可开启功能,在insert或update操作时都更新这个数据列的值(这个功能是给update_time用的,但是前提是配置好mysql的时区)。

For any TIMESTAMP or DATETIME column in a table, you can assign the current timestamp as the default value, the auto-update value, or both:

  1. An auto-initialized column is set to the current timestamp for inserted rows that specify no value for the column.
  2. An auto-updated column is automatically updated to the current timestamp when the value of any other column in the row is changed from its current value. An auto-updated column remains unchanged if all other columns are set to their current values. To prevent an auto-updated column from updating when other columns change, explicitly set it to its current value. To update an auto-updated column even when other columns do not change, explicitly set it to the value it should have (for example, set it to CURRENT_TIMESTAMP).

总结

这次项目虽然没有什么难度,但是最终还是掉到自己挖的沟里,好在周末甲方没有审核员上班,除了我以外并没有人知道数据出过问题(现在你也知道了)。
这次的事故出错的核心问题在于数据库图形软件用得太顺手了,以至于在加comments的时候点到了On Update,而在投产时并没有一个一个表的点开看结构,而是直接更新到生产环境服务器里。

Reference

11.3.5 Automatic Initialization and Updating for TIMESTAMP and DATETIME - MySQL v5.6

Contents
  1. 1. 前言
  2. 2. 发现问题
  3. 3. 数据修复
  4. 4. 关于on update
  5. 5. 总结
  6. 6. Reference