記一次線上問題 → 對 MySQL 的 ON UPDATE CURRENT_TIMESTAMP 的片面認知

青石路發表於2021-09-09

開心一刻

  老婆痛經,躺在沙發上,兩歲的女兒看著她問道

  女兒:媽媽,你怎麼了

  老婆:媽媽肚子痛

  女兒:哦,媽媽你頭疼

  老婆:不是頭疼,媽媽是肚子疼

  女兒用她的不鏽鋼飯碗砸向老婆的額頭,說道:媽媽,你哪裡疼

  老婆:頭疼,頭疼

  老婆幽怨的看著我,說道:這姑娘隨你還是隨我

  我低著頭,小聲地說道:我都被你欺負成啥樣了,你說姑娘隨誰?

問題背景

  需求背景

  需求:對商品的上架與下架進行管控,下架的商品不能進行銷售

    上架與下架的管控,在我負責的專案(單據系統)中實現;銷售的控制則是在另外一個專案(POS系統)中實現

    POS 系統定時的從單據系統中拉取資料,並對商品的銷售進行控制

  單據系統設計了兩張表:

記一次線上問題 → 對 MySQL 的 ON UPDATE CURRENT_TIMESTAMP 的片面認知
DROP TABLE IF EXISTS t_ware_on_off_bill;
CREATE TABLE `t_ware_on_off_bill` (
  `id` BIGINT(19) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `bill_code` VARCHAR(45) NOT NULL COMMENT '單據編號',
  `bill_type` TINYINT(2) NOT NULL DEFAULT 1 COMMENT '單據型別(1=下架,2=上架)',
  `bill_status` TINYINT(2) NOT NULL COMMENT '單據狀態(1=草稿,2=已提交,3=稽核中,4=已生效,5=已取消)',
  `is_delete` TINYINT(2) NOT NULL DEFAULT '2' COMMENT '是否刪除標識(1-是,2-否)',
    `note` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '備註',
  `create_user` BIGINT(19) NOT NULL COMMENT '建立人id',
  `create_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '建立時間',
  `modify_user` BIGINT(19) NOT NULL COMMENT '最終修改人',
  `modify_time` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '最終修改時間',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='商品上架下架單';

DROP TABLE IF EXISTS t_ware_on_off_bill_detail;
CREATE TABLE `t_ware_on_off_bill_detail` (
  `id` BIGINT(19) NOT NULL AUTO_INCREMENT COMMENT '自增主鍵',
  `bill_id` BIGINT(19) NOT NULL COMMENT '商品上架下架單的id',
  `ware_code` BIGINT(19) NOT NULL COMMENT '商品編號',
  `note` VARCHAR(255) DEFAULT NULL COMMENT '備註',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='商品上架下架單明細';
View Code

  實際上,表的欄位不止這麼多,但因為表的欄位的多少不影響問題的出現,所以也就簡化了表結構

  下游系統根據 modify_time 定時進行資料的增量同步( t_ware_on_off_bill 和 t_ware_on_off_bill_detail 都會進行更新)

  部分資料未同步

  結果出現了部分資料未同步的情況

  先來複現下問題,初始資料如下

  此時的 modify_time 的值是 2021-09-08 21:18:52.602 

  我們來執行下更新操作

  可以看到對 t_ware_on_off_bill 的更新結果是: 受影響的行: 0 , modify_time 並未進行更新,其值仍是 2021-09-08 21:18:52.602 

  但是 t_ware_on_off_bill_detail 是實實在在存在更新的

  這就導致下游系統通過 modify_time 沒有增量同步最新的商品明細

  問題來了:明明對 t_ware_on_off_bill 的 N 個欄位進行了 SET 操作,為什麼沒有記錄受影響(modify_time 為什麼不更新) 

探究真相

  我相信此時很多小夥伴都認為樓主是這個

  菜不可怕,怕的是我們不敢面對它;有問題,我們就去找原因,然後解決它(菜的好理直氣壯...)

  追查原因

  其實 MySQL 官方文件中有說明:11.2.6 Automatic Initialization and Updating for TIMESTAMP and DATETIME

 

   兩種情況會進行自動更新成系統當前時間

    1、insert 行時,該列沒有值

    2、該行的任意列的值改變了

  此時,相信大家都知道原因了吧

  雖然這個 SQL 很長,SET 了好幾個欄位,但是不滿足上述兩點中的任意一點,那麼 modify_time 也就不會更新成系統當前時間了

  解決問題

  原因是找到了,如何解決問題了?

  官方文件裡面也說明了,顯示的設值,也就是我們顯示的指定 modify_time 的值,像這樣

  我們來看看實際結果

  當然,解決方案不止這一種,各位可以在評論區暢所欲言

總結

  1、MySQL 自動設定成系統當前時間是有條件的,否則是不會更新的哦

    insert 行時,該列沒有值

    該行的任意列的值改變了

  2、給大家留個疑問:為什麼要有任意列的值改變了,MySQL 才會自動更新 modify_time 成當前系統時間,而不是隻要有 SET 就更新 modify_time 成當前系統時間

相關文章