業務說明
這樣一個業務場景,有一個抽獎活動,抽獎活動中如果完成一次分享的任務,就會增加一次抽獎機會。
前端判斷用戶分享成功后,會調用一次保存分享記錄的接口,將分享記錄入庫。
完成后,前端會調用獲取調用查詢【活動任務可完成次數】接口,如果任務可完成次數為0,則置灰分享按鈕。
本文原文鏈接地址: http://nullpointer.pw/數據庫與應用服務器時間不同步踩坑記.html
如圖所示:

定位問題
測試給我提了一個 BUG,在測試環境,完成分享任務后,重新調用【活動任務可完成次數】后,發現接口返回可完成次數仍然是 1,
但是過了好幾分鍾后,重新進入活動頁,接口返回了可完成次數為 0,分享按鈕也已經置灰不可點擊。
這就很奇怪了,一開始懷疑是緩存的問題,結果並不是,在測試環境遠程 Debug 后發現,每次分享成功后,查詢數據庫分享任務的完成次數竟然沒有查詢到數據,
而數據中確實存在了分享的記錄,將查詢 SQL 和查詢參數取出來放到 Navicat 中一查,結果是因為時間區間篩選掉了分享的那條記錄。
SQL 如下:
SELECT * from t_share_record where uid = "1234567" and activity_id = 38867247
and create_time between '2020-01-08 00:00:00' and '2020-01-08 19:18:29'
而數據庫中的那條分享記錄的create_time 是 2020-01-08 19:19:21, 這條記錄不在篩選的時間區間內,因而被過濾掉了。
問題原因
時序圖如下:

可以看到,分享保存記錄為第 8 步,但是重新查詢任務可完成接口是第 10 步,但目前的情況則是,第10步中查詢時的時間竟然要早於第 8 步數據入庫的時間。難道插入數據竟然要這么久?也不至於耗費近一分鍾吧!
於是懷疑是數據庫時間問題,在MySQL執行查詢命令
select now();
然后,在部署應用的服務器上執行命令
date
查看結果,果然二者時間相差了近一分鍾。最終的原因就是:因為數據庫和應用服務器不在同一台服務器上,而其他測試人員修改了應用服務器的時間,導致兩個服務器時間不一致從而出現這個問題。想到這里,馬上向運維確認線上服務器時間與數據庫時間是否同步,還好,回答我的是同步的,心里的石頭算放下了。
解決問題
查看插入分享記錄的 Mybatis 中XML如下
insert into t_share_record(uid, activity_id, create_time) values(#{uid}, #{activityId}, now())
這樣寫是沒問題的,但是根據時間段篩選數據時,時間區間卻又是從應用服務器生成傳遞參數傳入SQL的,Mybatis 中XML如下:
SELECT * from t_share_record where uid = #{uid} and activity_id = #{activityId}
and create_time between #{beginTime} and #{endTime}
為了避免以上這種因為應用服務器與數據庫時間不一致導致的問題,這里的SQL篩選時間的結束時間也通過數據庫服務器獲取。
SELECT * from t_share_record where uid = #{uid} and activity_id = #{activityId}
and create_time between #{beginTime} and now()
當然,為了防止出現更多類似的問題,應用服務器與數據庫服務器的時間一定要通過時間同步設置保持完全一致才是最合理的。
希望對你有所幫助!
