更新時間相差8個小時

下面的java代碼在updateFill方法里面生成的modifiedTime時間是當前時間是正確的,為什么到service層testCommonFieldAutoUpdate方法里面去更新的時候modifiedTime就差8個小時呢?代碼如下所示:

@Slf4j
@Component
public class MpMetaObjectHandler implements MetaObjectHandler {
? ??
? ? @Override
? ? public void insertFill(MetaObject metaObject) {
? ? ? ? //通用填充
? ? ? ? this.setFieldValByName("createdTime", LocalDateTime.now(), metaObject);
? ? ? ? //嚴格模式:根據更新策略填充
? ? ? ? this.strictInsertFill(metaObject,"modifiedTime",LocalDateTime::now,LocalDateTime.class);
? ? ? ? this.strictInsertFill(metaObject,"tenantNo",()-> HttpHeaderUtil.getHeaderValue("tenant-no"),String.class);

? ? }
? ? /**
? ? ?* ?使用mp的更新類api時會回調
? ? ?* ?update user set address=?,modified_time=? where id=?
? ? ?*/
? ? @Override
? ? public void updateFill(MetaObject metaObject) {
? ? ? ? this.strictUpdateFill(metaObject, "modifiedTime", () ->
? ? ? ? ? ? ? ? Date.from(ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).toInstant()), Date.class);
? ? }

? ??
? ? @Override
? ? public MetaObjectHandler strictFillStrategy(MetaObject metaObject, String fieldName, Supplier<?> fieldVal) {
? ? ? ? Object obj = fieldVal.get();
? ? ? ? if (Objects.nonNull(obj)) {
? ? ? ? ? ? metaObject.setValue(fieldName, obj);
? ? ? ? }
? ? ? ? return this;
? ? }
}

service層代碼如下所示:
@Service
@Slf4j
public class UserRoadServiceImpl extends ServiceImpl<UserRoadMapper, UserDO> implements UserRoadService {
import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.project.mapper.UserRoadMapper;
import org.project.roadjava.ramble.test.bean.entry.UserDO;
import org.project.roadjava.ramble.test.bean.req.user.AddUserRequest;
import org.project.roadjava.ramble.test.bean.req.user.UpdateUserRequest;
import org.project.roadjava.ramble.test.ex.BizEx;
import org.project.roadjava.ramble.test.service.UserRoadService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
@Override
? ? @Transactional(rollbackFor = Exception.class)
? ? public void testCommonFieldAutoUpdate(UpdateUserRequest updateReq) {
? ? ? ? UserDO existedEntity = getById(updateReq.getId());
? ? ? ?
? ? ? ? if (existedEntity == null) {
? ? ? ? ? ? throw new BizEx("數據不存在");
? ? ? ? }
? ? ? ? existedEntity.setAddress(updateReq.getAddress());
? ? ? ? existedEntity.setGender(updateReq.getGender());
? ? ? ? updateById(existedEntity);
? ? }
}

你這個問題非常經典,也具有一定的代表性 —— 在 MetaObjectHandler 中設置的時間是正確的(東八區時間),但在 Service 層通過 updateById() 更新時,數據庫中記錄的 modifiedTime 卻少了 8 小時。

我們來一步步分析問題的本質和根本原因。

? 現象總結
場景?? ?時間值?? ?是否正確
MetaObjectHandler.updateFill() 中生成時間?? ?Date.from(ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).toInstant())?? ?? 正確
數據庫中的 modified_time 字段?? ?存入的是 UTC 時間(比北京時間晚 8 小時)?? ?? 錯誤
Java 實體類字段類型?? ?Date?? ??? 潛在問題
🧩 核心問題:java.util.Date 是一個“無時區”的包裝器,但內部保存的是 UTC 時間戳
關鍵點:
new Date() 或 Date.from(...) 創建的對象,其本質是一個從 1970-01-01T00:00:00Z 開始的毫秒數(即 Unix 時間戳),它本身不包含任何時區信息。
當你在代碼中打印 Date.toString() 時,它會根據 JVM 的默認時區格式化輸出,所以看起來像是本地時間。
但是當這個 Date 被寫入數據庫時,JDBC 驅動、MyBatis、數據庫連接池等組件可能會以不同的方式處理這個時間值,導致出現時區偏差。
🔍 為什么 MetaObjectHandler 中設置的是正確時間?
你的這段代碼:

Java
深色版本
this.strictUpdateFill(metaObject, "modifiedTime", () ->
? ? ? ? Date.from(ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).toInstant()), Date.class);
實際上是這樣做的:

獲取了當前東八區時間(ZonedDateTime.now(ZoneId.of("Asia/Shanghai")))
轉換為 Instant(這是標準的 UTC 時間)
再轉換為 Date(仍然是基于 UTC 時間戳)
此時,Date 對象表示的是一個 UTC 時間點。但由于你在日志或調試中看到的是類似 Tue Jun 04 15:30:00 CST 2025 這樣的字符串,這其實是 Date.toString() 使用了 JVM 默認時區(可能是 Asia/Shanghai)進行展示,因此看起來是正確的。

💥 為什么 Service 層更新的時候卻差了 8 小時?
當你執行如下代碼時:

Java
深色版本
UserDO existedEntity = getById(updateReq.getId());
existedEntity.setAddress(updateReq.getAddress());
updateById(existedEntity);
此時:

MyBatis Plus 會將 existedEntity 中的 modifiedTime 字段(類型是 Date)直接傳給 JDBC 驅動;
如果數據庫字段是 DATETIME 類型,則 JDBC 驅動通常會將 Date 直接當作 UTC 時間 來處理(特別是 MySQL 8+ 的行為);
所以即使你存入的是 Date.from(ZonedDateTime.now(...).toInstant()),數據庫最終可能認為這是一個 UTC 時間,而不是東八區時間;
最終顯示出來就少了 8 小時。
? 解決方案
? 推薦做法一:統一使用 LocalDateTime + TypeHandler(推薦)
1. 修改實體類字段為 LocalDateTime
Java
深色版本
private LocalDateTime modifiedTime;
2. 在自動填充中使用 LocalDateTime::now
Java
深色版本
@Override
public void updateFill(MetaObject metaObject) {
? ? this.strictUpdateFill(metaObject, "modifiedTime", LocalDateTime::now, LocalDateTime.class);
}
3. 添加 TypeHandler 支持
確保你的項目中引入了以下依賴(用于支持 LocalDateTime 到數據庫的映射):

Xml
深色版本
<dependency>
? ? <groupId>com.baomidou</groupId>
? ? <artifactId>mybatis-plus-typehandlers-jsr310</artifactId>
? ? <version>3.5.3</version> <!-- 請根據你的 MP 版本調整 -->
</dependency>
MyBatis Plus 會自動識別并注冊這些處理器。

4. 數據庫字段類型應為 DATETIME 或 TIMESTAMP
MySQL 推薦使用 TIMESTAMP,它會自動存儲為 UTC 并在查詢時根據連接參數轉為本地時間。

? 替代做法二:繼續使用 Date,但修改 JDBC 連接配置指定時區
如果你堅持使用 Date 類型,可以在數據庫連接字符串中顯式指定時區。

示例(MySQL):
Properties
深色版本
jdbc:mysql://localhost:3306/your_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
serverTimezone=GMT%2B8 表示服務器時間偏移量為 UTC+8,這樣 JDBC 驅動就知道如何正確地把 Date 映射到數據庫時間。
📌 總結對比
方案?? ?類型?? ?優點?? ?缺點
? 使用 LocalDateTime + TypeHandler?? ?推薦?? ?語義清晰,避免時區混亂,Java 8 原生支持?? ?需要引入額外依賴
? 使用 Date + JDBC 設置時區?? ?可行?? ?不改動現有代碼結構?? ?容易遺漏或配置錯誤
? 繼續用 Date 且不改配置?? ???? ?無需改代碼?? ?極容易出現時區偏差
? 建議操作順序
把 modifiedTime 字段改為 LocalDateTime 類型;
修改自動填充邏輯為 LocalDateTime::now;
引入 mybatis-plus-typehandlers-jsr310;
數據庫字段保持為 DATETIME 或改為 TIMESTAMP;
(可選)數據庫連接串加上 serverTimezone=GMT%2B8。
🧪 如何驗證是否修復成功?
在 Debug 模式下查看 modifiedTime 字段是否是預期時間;
查看數據庫記錄是否與代碼中一致;
日志中打印出 modifiedTime,確認輸出格式和時區;
多臺不同系統時區的機器測試,確認一致性。
如你能提供:

數據庫字段定義(DATETIME / TIMESTAMP)
使用的數據庫類型及版本(MySQL 8?PostgreSQL?)
MyBatis Plus 版本
數據庫連接 URL 和驅動版本
我可以進一步幫你做更精準的建議。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/82715.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/82715.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/82715.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Windows逆向工程提升之IMAGE_TLS_DIRECTORY

公開視頻 -> 鏈接點擊跳轉公開課程博客首頁 -> ???鏈接點擊跳轉博客主頁 目錄 TLS的作用 TLS的實現 靜態 TLS?? 動態 TLS?? 內部實現 回調機制 TLS Directory 的結構 TLS的作用 TLS (Thread Local Storage) 是一種用于為多線程應用程序提供線程獨立存儲空…

云效流水線Flow使用記錄

概述 最近在頻繁使用阿里云云效的幾款產品&#xff0c;如流水線。之前寫過一篇&#xff0c;參考云效流水線緩存問題。 這篇文章來記錄更多問題。 環境變量 不管是云效流水線Flow還是應用交付AppStack&#xff08;基于流水線&#xff0c;后文不再贅述&#xff09;&#xff0…

Android中獲取控件尺寸進階方案

在Android開發中,很多場景都需要獲取控件(View)的寬高信息,比如動態布局調整、動畫效果實現等。然而,直接在Activity的onCreate()中調用控件的getWidth()或getHeight()`方法,得到結果卻是0,因為控件還沒完成布局測量。 本文總結了幾種獲取控件大小的實用方法,并對各方…

android 輸入系統

一、輸入系統的核心角色與分層架構 Android 輸入系統的本質是橋梁&#xff1a;一端連接硬件驅動產生的原始事件&#xff0c;另一端將事件精準派發給應用窗口。整個過程涉及三層架構和多個關鍵組件&#xff0c;可類比為 “快遞分揀系統”&#xff1a; 1. 硬件與內核層&#xf…

ubuntu中,c和c+程序,預編譯、編譯、鏈接和運行命令

目錄 安裝編譯器一.c編譯運行&#xff08;粗暴簡單&#xff09;1.編寫 C 程序&#xff1a;2. 預處理&#xff1a;3.編譯&#xff1a;4. 匯編&#xff1a;5. 鏈接&#xff1a;6.運行 二.c編譯運行&#xff08;粗暴簡單&#xff09;1.編寫 C 程序&#xff1a;2.預處理&#xff1a…

【FastAPI】--2.進階教程(一)

【FastAPI】--基礎教程-CSDN博客 app.get和post的參數&#xff1a; 參數類型說明pathstr路由路徑&#xff08;如 "/marks"&#xff09;&#xff0c;必填。response_modelType[T]定義響應數據的模型&#xff08;如 percent&#xff09;&#xff0c;會自動校驗和序列…

KT6368A通過藍牙芯片獲取手機時間詳細說明,對應串口指令舉例

一、功能簡介 KT6368A雙模藍牙芯片支持連接手機&#xff0c;獲取手機的日期、時間信息&#xff0c;可以同步RTC時鐘 1、無需安裝任何app&#xff0c;直接使用系統藍牙即可實現 2、同時它不影響音頻藍牙&#xff0c;還支持一些簡單的AT指令進行操作 3、實現的方式&#xff1…

【平面波導外腔激光器專題系列】用于光纖傳感的低噪聲PLC外腔窄線寬激光器

----翻譯自Mazin Alalusi等人的文章 摘要 高性價比的 1550 nm DWDM平面外腔 &#xff08;PLANEX&#xff09; 激光器是干涉測量、布里淵、LIDAR 和其他光傳感應用的最佳選擇。其線寬<3kHz、低相位/頻率噪聲和極低的RIN。 簡介 高性能光纖分布式傳感技術是在過去幾年中開發…

企業微信內部網頁開發流程筆記

背景 基于ai實現企微側邊欄和工作臺快速問答小助&#xff0c;需要h5開發&#xff0c;因為流程不清楚摸索半天&#xff0c;所以記錄一下 一、網頁授權登錄 1. 配置步驟 1.1 設置可信域名 登錄企業微信管理后臺 進入"應用管理" > 選擇開發的具體應用 > “網…

WORD 轉 PDF 工具:排版 / 圖片 / 表格批量轉換提升辦公效率

各位辦公小能手們&#xff0c;今天來聊聊文檔工具里的WORD轉PDF工具&#xff01;這玩意兒到底是干啥的呢&#xff1f;咱來好好說道說道。 先說核心功能。第一個就是格式轉換&#xff0c;能把Word文檔轉換成PDF&#xff0c;不管是格式、排版&#xff0c;還是圖片、表格啥的&…

從逆流監測到智慧用電:ADL200N-CT系列單相導軌表賦能家庭綠色能源

在新能源浪潮席卷全球的當下&#xff0c;陽臺光伏以及家庭儲能&#xff08;戶儲&#xff09;系統逐漸成為眾多追求綠色生活、渴望實現能源自主家庭的新選擇。它不僅能有效利用太陽能等清潔能源&#xff0c;還能在用電高峰時段為家庭提供穩定電力支持&#xff0c;降低用電成本。…

std::thread的說明與示例

源于通義千問 在 C 中&#xff0c;std::thread 支持傳遞多種類型的函數作為線程入口點。你可以傳遞普通函數、類的成員函數、Lambda 表達式、函數對象&#xff08;仿函數&#xff09;等。以下是詳細的說明和示例。 1. 傳遞普通函數 普通函數是最簡單的用法。 示例 #include…

【Day38】

DAY 38 Dataset和Dataloader類 對應5. 27作業 知識點回顧&#xff1a; Dataset類的__getitem__和__len__方法&#xff08;本質是python的特殊方法&#xff09;Dataloader類minist手寫數據集的了解 作業&#xff1a;了解下cifar數據集&#xff0c;嘗試獲取其中一張圖片 import …

RabbitMQ 集群與高可用方案設計(三)

五、高可用方案設計與實現 &#xff08;一&#xff09;負載均衡與代理 1. HAProxy 配置 HAProxy 是一款廣泛應用的開源負載均衡器和代理服務器&#xff0c;它能夠實現對 RabbitMQ 集群節點的負載均衡和健康檢查&#xff0c;有效提高系統的可用性和性能。以下是使用 HAProxy …

機器學習第二十四講:scikit-learn → 機器學習界的瑞士軍刀

機器學習第二十四講&#xff1a;scikit-learn → 機器學習界的瑞士軍刀 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1a;超詳細手把手指南 Scikit-…

百度ocr的簡單封裝

百度ocr地址 以下代碼為對百度ocr的簡單封裝,實際使用時推薦使用baidu-aip 百度通用ocr import base64 from enum import Enum, unique import requests import logging as logunique class OcrType(Enum):# 標準版STANDARD_BASIC "https://aip.baidubce.com/rest/2.0…

Ubuntu20.04 gr-gsm完整安裝教程

gr-gsm完整安裝教程 安裝gnuradio3.8安裝依賴項指定gnuradio源安裝gnuradio 安裝gr-gsm安裝依賴項安裝gr-gsm修改環境變量 安裝成功 安裝gnuradio3.8 安裝依賴項 sudo apt install git cmake g libboost-all-dev libgmp-dev swig python3-numpy python3-mako python3-sphinx …

(自用)Java學習-5.15(模糊搜索,收藏,購物車)

1. 模糊搜索商品功能 前端實現&#xff1a; 通過解析URL參數&#xff08;如search聯想&#xff09;獲取搜索關鍵字&#xff0c;發送AJAX GET請求到后端接口/product/searchGoodsMessage。 動態渲染搜索結果&#xff1a;若結果非空&#xff0c;循環遍歷返回的商品數據&#xff…

STM32 TIM 定時器深度剖析:結構、時基、中斷與應用開發(超形象詳解)

文章目錄 定時器&#xff08;TIM&#xff09;定時器種類與分布定時器的基本結構時基單元時基單元基本結構計數器計數方向時基單元時鐘來源計算寄存器預加載機制 自制延時函數獲取單片機當前時間實現延遲函數初始化定時器3的時基單元配置中斷編寫中斷響應函數測試延遲函數 定時器…

Java使用minio上傳整個目錄下的所有內容

目錄 1、添加相關配置 2、添加依賴 3、實現方法 1??基礎版&#xff1a; 2??優化版&#xff08;推薦使用&#xff09;&#xff1a; 3??上傳遠程主機上的目錄內容&#xff1a; 4??直接上傳遠程主機中的目錄內容 業務背景&#xff1a;需要需要minio進行上傳指定目錄下所有…