日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

JDBC与mysql同为CST时区导致数据库时间和客户端时间差13或者14小时

發布時間:2025/3/21 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JDBC与mysql同为CST时区导致数据库时间和客户端时间差13或者14小时 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

摘要
線上排查問題時候碰到一個奇怪的問題,代碼中讀取一天的記錄。代碼中設置時間是從零點到夜里二十四點。但是讀取出來的記錄的開始是既然是從13點開始的。然后看了JDBC的源碼發現主要原因是Mysql的CST時間與Java中CST時間是不一樣的,下面給出問題的排查過程。

情景再現

1、代碼中用的java.util.Date類型、換成TimeStamp類型也沒有解決問題
2、數據庫中用的TimeStamp類型
3、mysql 版本5.6.x
4、jdk版本1.8
5、mysql-connector-java 8.0.13
我的數據庫時區信息如下:

select @@system_time_zone; +--------------------+ | @@system_time_zone | +--------------------+ | CST | +--------------------+ 1 row in set (4.81 sec)mysql> select @@time_zone; +-------------+ | @@time_zone | +-------------+ | SYSTEM | +-------------+ 1 row in set (0.04 sec)

CST時間

CST時間有四種解釋,所以不同項目中可能代碼的意義不一樣,比如Mysql和Java。這也是這次錯誤的主要原因。Java和Mysql協商時區時把Mysql的CST時間當成了美國中部時間既UTC-5(美國從“3月11日”至“11月7日”實行夏令時,美國中部時間改為 UTC-05:00,其他時候是UTC-06:00)。我們國家是UTC+08:00 時區,所以差了13個小時(13小時還是14小時,取決于你傳遞給數據庫的時間),

  • 美國中部時間 Central Standard Time (USA) UTC-05:00 / UTC-06:00
  • 澳大利亞中部時間 Central Standard Time (Australia) UTC+09:30
  • 中國標準時 China Standard Time UTC+08:00
  • 古巴標準時 Cuba Standard Time UTC-04:00

CST in Java

SimpleDateFormat f1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); f1.setTimeZone(TimeZone.getTimeZone("CST")); System.out.println(f1.parse("2015-09-01 00:00:00"));

上面代碼的輸出如下:

Tue Sep 01 13:00:00 CST 2015

比實際的時間多了13個小時。所以你在Java中的時間被認為是UTC-5時間,而數據庫任務時間是UTC-8時間。這就是我們上面錯誤的原因。

源碼分析

關鍵的代碼在ConnectionImpl類中,代碼如下,已經去掉一些無關重要的代碼

private void initializePropsFromServer() throws SQLException {String connectionInterceptorClasses = this.propertySet.getStringProperty(PropertyKey.connectionLifecycleInterceptors).getStringValue();this.session.setSessionVariables();this.session.loadServerVariables(this.getConnectionMutex(), this.dbmd.getDriverVersion()); //查詢數據庫一些重要的系統配置this.autoIncrementIncrement = this.session.getServerSession().getServerVariable("auto_increment_increment", 1);this.session.buildCollationMapping();this.session.getProtocol().initServerSession();// 初始化會話,協商時區代碼就在里面checkTransactionIsolationLevel();this.session.checkForCharsetMismatch();this.session.configureClientCharacterSet(false);handleAutoCommitDefaults();

其中this.session.loadServerVariables(this.getConnectionMutex(), this.dbmd.getDriverVersion());查詢Mysql重要配置。比如時區。具體查詢的信息如下:

StringBuilder queryBuf = new StringBuilder(versionComment).append("SELECT");queryBuf.append(" @@session.auto_increment_increment AS auto_increment_increment");queryBuf.append(", @@character_set_client AS character_set_client");queryBuf.append(", @@character_set_connection AS character_set_connection");queryBuf.append(", @@character_set_results AS character_set_results");queryBuf.append(", @@character_set_server AS character_set_server");queryBuf.append(", @@collation_server AS collation_server");queryBuf.append(", @@collation_connection AS collation_connection");queryBuf.append(", @@init_connect AS init_connect");queryBuf.append(", @@interactive_timeout AS interactive_timeout");if (!versionMeetsMinimum(5, 5, 0)) {queryBuf.append(", @@language AS language");}queryBuf.append(", @@license AS license");queryBuf.append(", @@lower_case_table_names AS lower_case_table_names");queryBuf.append(", @@max_allowed_packet AS max_allowed_packet");queryBuf.append(", @@net_write_timeout AS net_write_timeout");if (!versionMeetsMinimum(8, 0, 3)) {queryBuf.append(", @@query_cache_size AS query_cache_size");queryBuf.append(", @@query_cache_type AS query_cache_type");}queryBuf.append(", @@sql_mode AS sql_mode");queryBuf.append(", @@system_time_zone AS system_time_zone");queryBuf.append(", @@time_zone AS time_zone");if (versionMeetsMinimum(8, 0, 3) || (versionMeetsMinimum(5, 7, 20) && !versionMeetsMinimum(8, 0, 0))) {queryBuf.append(", @@transaction_isolation AS transaction_isolation");} else {queryBuf.append(", @@tx_isolation AS transaction_isolation");}queryBuf.append(", @@wait_timeout AS wait_timeout");

this.session.getProtocol().initServerSession();這就是協商時區的代碼,也是我們重點需要關注的代碼。如下

public void configureTimezone() {// 獲取mysql時區配置,結果是SYSTEMString configuredTimeZoneOnServer = this.serverSession.getServerVariable("time_zone");//因為我的數據庫time_zone是SYSTEM,所以就使用system_time_zone作為數據的時區,如一開始mysql查詢結果,時區為CST,既configuredTimeZoneOnServer=CSTif ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {configuredTimeZoneOnServer = this.serverSession.getServerVariable("system_time_zone");}// 從配置中查找你對時區的配置,如果你沒有這里為null。getPropertySet()就保存了你的數據庫用戶名、密碼、字符編碼啊等你在url鏈接中設置的屬性String canonicalTimezone = getPropertySet().getStringProperty(PropertyKey.serverTimezone).getValue();//因為我沒有配置serverTimezone屬性,所以canonicalTimezone==nullif (configuredTimeZoneOnServer != null) {// user can override this with driver properties, so don't detect if that's the caseif (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) {try { //協商java中的時區,因為Mysql為CST,所以這里也是CSTcanonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor());} catch (IllegalArgumentException iae) {throw ExceptionFactory.createException(WrongArgumentException.class, iae.getMessage(), getExceptionInterceptor());}}}if (canonicalTimezone != null && canonicalTimezone.length() > 0) { //將剛剛得到的Java的時區設置到會話中this.serverSession.setServerTimeZone(TimeZone.getTimeZone(canonicalTimezone));}this.serverSession.setDefaultTimeZone(this.serverSession.getServerTimeZone());}

再來看一下,如果給sql語句的占位符中傳遞值的時候代碼

this.tsdf = TimeUtil.getSimpleDateFormat(this.tsdf, "''yyyy-MM-dd HH:mm:ss", targetCalendar,targetCalendar != null ? null : this.session.getServerSession().getDefaultTimeZone());StringBuffer buf = new StringBuffer();buf.append(this.tsdf.format(x));if (this.session.getServerSession().getCapabilities().serverSupportsFracSecs()) {buf.append('.');buf.append(TimeUtil.formatNanos(x.getNanos(), 6));}buf.append('\'');setValue(parameterIndex, buf.toString(), MysqlType.TIMESTAMP);

代碼中把Date或者TimeStamp轉換為String,而且用了協商的時區。
分析到這里,問題基本上說清楚了。那么我們如何解決這個問題呢?

總結

1、數據庫時區最好不要設置成CST,以免出現上面的錯誤
2、當數據庫中的時間用的是時間類型時候,Java中可以用String,但是不適應做國際化
3、在數據庫連接字符串中設置時區。如下(推薦的方式):

jdbc:mysql://xxxx:3306/table_name?serverTimezone=Asia/Shanghai&useUnicode=true&charact



作者:sunny4handsome
鏈接:https://www.jianshu.com/p/c37b11472151
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權并注明出處。

總結

以上是生活随笔為你收集整理的JDBC与mysql同为CST时区导致数据库时间和客户端时间差13或者14小时的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲一区精品视频在线观看 | 亚洲一区美女 | 婷婷亚洲一区 | 欧美性xxxxx极品少妇 | 色屁屁影院www国产高清麻豆 | 国产传媒一区 | 欧美 日韩 国产 激情 | 大黑人交交护士xxxxhd | 麻豆av电影网 | 麻豆国产网站 | 波多野42部无码喷潮 | 久久五月视频 | 看黄网站在线观看 | 亚洲精品偷拍视频 | 开心激情播播网 | 日本大尺度电影免费观看全集中文版 | 国内毛片毛片毛片 | 国内精品视频一区 | 日韩国产成人无码av毛片 | 超碰在线网址 | 人人草人人爽 | hd极品free性xxx护士 | 波多野结衣激情视频 | √8天堂资源地址中文在线 欧美精品在线一区二区 | 女人床技48动态图 | 无码内射中文字幕岛国片 | 夜夜高潮夜夜爽 | 日韩一区二区三区高清 | 伊人爱爱网 | 三区在线 | 特淫毛片| av网站地址 | 欧美日韩一二三 | 欧美精品一级二级三级 | 麻豆免费av | 国产乱码精品一区二区三区不卡 | 怡红院最新网址 | 成人亚洲精品 | 日韩极品视频在线观看 | 日韩午夜精品视频 | 国产极品久久久 | 蜜桃av噜噜一区二区三区网址 | 一区二区激情 | 国产一级影院 | 天天天综合网 | 日韩av毛片在线观看 | 蜜桃tv一区二区三区 | 韩国三级丰满少妇高潮 | 欧美性网址 | 日本精品一区在线 | 特黄特色大片免费视频大全 | 一级黄色片大全 | 涩涩涩在线观看 | 亚洲一二三视频 | 欧美老肥熟 | 男女羞羞的视频 | 免费av网址在线观看 | av一区二区三区在线 | 爱爱一区 | 欧美性生交xxxxx | 久久久视频6r | 日韩欧美精品免费 | www.自拍 | 超碰97人人射妻 | 日本三级欧美三级 | 九九精品在线观看 | 欧美三级图片 | 国产色 | 日韩精品乱码久久久久久 | 国内偷拍精品视频 | 欧美69精品久久久久久不卡 | 国产精品久久久久久久久久久久久久久久久 | 黄色工厂这里只有精品 | 黄色片18 | jizz自拍| 国产一区=区 | 可以免费看的av网站 | 新天堂网 | 亚洲天堂成人网 | 国产最新地址 | 木下凛凛子av一区二区三区 | 中国一级免费毛片 | 又大又粗弄得我出好多水 | 天堂网成人 | 天天插夜夜操 | 浪潮av色 | 中文字幕久久熟女蜜桃 | 香蕉视频在线网址 | 五月天啪啪 | 公车乳尖揉捏酥软呻吟 | 天天综合在线视频 | 伊人网综合 | 国产影视一区 | 日韩性猛交ⅹxxx乱大交 | 男人的天堂影院 | 69xx视频在线观看 | 新中文字幕 | 95视频在线观看 | 亚洲精品一区二三区 |