最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關(guān)于Java中的mysql時(shí)區(qū)問題詳解

 更新時(shí)間:2020年05月22日 08:51:13   作者:AddoZhang  
這篇文章主要給大家介紹了關(guān)于Java中mysql時(shí)區(qū)問題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

話說(shuō)工作十多年,mysql 還真沒用幾年。起初是外企銀行,無(wú)法直接接觸到 DB;后來(lái)一直從事架構(gòu)方面,也多是解決問題為主。

這次搭建海外機(jī)房,圍繞時(shí)區(qū)大家做了一番討論。不說(shuō)最終的結(jié)果是什么,期間有同事認(rèn)為 DB 返回的是 UTC 時(shí)間。

這里簡(jiǎn)單做個(gè)驗(yàn)證,順便看下時(shí)區(qū)的問題到底是如何處理。

環(huán)境

openjdk version “1.8.0_242”
mysql-connector-java “8.0.20”
mysql “5.7” 時(shí)區(qū) TZ=Europe/London

本地時(shí)區(qū) GMT+8

創(chuàng)建個(gè)簡(jiǎn)單的庫(kù)test及表user, 表結(jié)構(gòu)如下:

CREATE TABLE `user` (
 `name` varchar(50) NOT NULL,
 `birth_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1

插入一條測(cè)試數(shù)據(jù):

mysql> insert into `user`
  -> values ('Tom', time('2020-05-15 08:00:00'));
Query OK, 1 row affected (0.01 sec)

mysql> select * from user;
+------+---------------------+
| name | birth_date     |
+------+---------------------+
| Tom | 2020-05-14 08:00:00 |
+------+---------------------+
1 row in set (0.00 sec)

測(cè)試代碼:

Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "root");
Statement stmt = conn.createStatement();
stmt.execute("select * from user where name = 'Tom'");
ResultSet rs = stmt.getResultSet();
while (rs.next()) {
  Timestamp timestamp = rs.getTimestamp("birth_date");
  System.out.println(timestamp.toLocalDateTime().toString());
}

執(zhí)行結(jié)果:

2020-05-14T15:00

分析

程序的執(zhí)行過(guò)程同時(shí)用 wireshark 抓了包。可以看到一次查詢,做了這么多次的交互(包含了會(huì)話初始化)。這里可以看到 #177 的交互返回查詢的結(jié)果:Tom 2020-05-14 08:00:00,與 DB 中的數(shù)據(jù)相符??梢?,返回的并不是 UTC 時(shí)間。

在 TCP 抓包結(jié)果中 #155 的查詢語(yǔ)句:

/* mysql-connector-java-8.0.20 (Revision: afc0a13cd3c5a0bf57eaa809ee0ee6df1fd5ac9b) */
SELECT @@session.auto_increment_increment AS auto_increment_increment,
    @@character_set_client       AS character_set_client,
    @@character_set_connection     AS character_set_connection,
    @@character_set_results      AS character_set_results,
    @@character_set_server       AS character_set_server,
    @@collation_server         AS collation_server,
    @@collation_connection       AS collation_connection,
    @@init_connect           AS init_connect,
    @@interactive_timeout       AS interactive_timeout,
    @@license             AS license,
    @@lower_case_table_names      AS lower_case_table_names,
    @@max_allowed_packet        AS max_allowed_packet,
    @@net_write_timeout        AS net_write_timeout,
    @@performance_schema        AS performance_schema,
    @@query_cache_size         AS query_cache_size,
    @@query_cache_type         AS query_cache_type,
    @@sql_mode             AS sql_mode,
    @@system_time_zone         AS system_time_zone,
    @@time_zone            AS time_zone,
    @@transaction_isolation      AS transaction_isolation,
    @@wait_timeout           AS wait_timeout;

服務(wù)端返回的 time_zone 為 BST。與本地時(shí)區(qū)的轉(zhuǎn)換,由 mysql 的 connector 自動(dòng)完成。

進(jìn)階

時(shí)區(qū)自動(dòng)轉(zhuǎn)換

實(shí)現(xiàn)源碼:

ResultSetImpl源碼

this.defaultTimestampValueFactory = new SqlTimestampValueFactory(pset, null, this.session.getServerSession().getServerTimeZone());@Overridepublic Timestamp getTimestamp(int columnIndex) throws SQLException {
  checkRowPos();
  checkColumnBounds(columnIndex);  return this.thisRow.getValue(columnIndex - 1, this.defaultTimestampValueFactory);
}

如何確認(rèn)服務(wù)端時(shí)區(qū)?

使用會(huì)話中的服務(wù)端時(shí)區(qū)進(jìn)行服務(wù)端時(shí)區(qū)。會(huì)話初始化時(shí)會(huì)進(jìn)行時(shí)區(qū)的確認(rèn),比如前面獲取的到BST。確認(rèn)時(shí)區(qū)的邏輯在NativeProtocol#configureTimezone()中:

public void configureTimezone() {
  #從mysql的響應(yīng)獲取 time_zone 和 system_time_zone 的設(shè)置
  String configuredTimeZoneOnServer = this.serverSession.getServerVariable("time_zone");

  if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
    configuredTimeZoneOnServer = this.serverSession.getServerVariable("system_time_zone");
  }

  #從 jdbc url 參數(shù) serverTimezone 獲取時(shí)區(qū)
  String canonicalTimezone = getPropertySet().getStringProperty(PropertyKey.serverTimezone).getValue();

  if (configuredTimeZoneOnServer != null) {
    //如果 jdbc url 中未通過(guò) serverTimezone 指定時(shí)區(qū)。則從TimeZoneMapping.properties中獲取mysql 回傳的時(shí)區(qū)縮寫對(duì)應(yīng)的標(biāo)準(zhǔn)時(shí)區(qū),比如此處的 BST => Europe/London
    //會(huì)出現(xiàn)無(wú)法映射的情況,不如 CEST 無(wú)法映射到 => Europe/Berlin,可以指定自定義的 Properties 文件進(jìn)行映射
    // user can override this with driver properties, so don't detect if that's the case
    if (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone)) {
      try {
        canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, getExceptionInterceptor());
      } catch (IllegalArgumentException iae) {
        throw ExceptionFactory.createException(WrongArgumentException.class, iae.getMessage(), getExceptionInterceptor());
      }
    }
  }
  
  //如果 jdbc url 中通過(guò) serverTimezone 指定了時(shí)區(qū),則優(yōu)先使用該時(shí)區(qū)
  if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
    this.serverSession.setServerTimeZone(TimeZone.getTimeZone(canonicalTimezone));

    //
    // The Calendar class has the behavior of mapping unknown timezones to 'GMT' instead of throwing an exception, so we must check for this...
    //
    if (!canonicalTimezone.equalsIgnoreCase("GMT") && this.serverSession.getServerTimeZone().getID().equals("GMT")) {
      throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.9", new Object[] { canonicalTimezone }),
          getExceptionInterceptor());
    }
  }

}

關(guān)于 serverTimezone 的官方說(shuō)明

Override detection/mapping of time zone. Used when time zone from server doesn't map to Java time zone

修改一下 jdbc url,通過(guò)serverTimezone指定時(shí)區(qū)為 GMT+8:jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&useSSL=false

再次執(zhí)行代碼:

2020-05-14T08:00

總結(jié)

到此這篇關(guān)于關(guān)于Java中mysql時(shí)區(qū)問題的文章就介紹到這了,更多相關(guān)Java中mysql時(shí)區(qū)問題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合mybatis-plus實(shí)現(xiàn)分頁(yè)查詢功能

    SpringBoot整合mybatis-plus實(shí)現(xiàn)分頁(yè)查詢功能

    這篇文章主要介紹了SpringBoot整合mybatis-plus實(shí)現(xiàn)分頁(yè)查詢功能,pringBoot分頁(yè)查詢的兩種寫法,一種是手動(dòng)實(shí)現(xiàn),另一種是使用框架實(shí)現(xiàn),現(xiàn)在我將具體的實(shí)現(xiàn)流程分享一下,需要的朋友可以參考下
    2023-11-11
  • javaWeb連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)簡(jiǎn)單登陸注冊(cè)功能的全過(guò)程

    javaWeb連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)簡(jiǎn)單登陸注冊(cè)功能的全過(guò)程

    初學(xué)javaWeb,老師留下一小作業(yè),用JAVA實(shí)現(xiàn)與服務(wù)器端交互,實(shí)現(xiàn)登錄和注冊(cè)功能,下面這篇文章主要給大家介紹了關(guān)于javaWeb連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)簡(jiǎn)單登陸注冊(cè)功能的相關(guān)資料,需要的朋友可以參考下
    2022-06-06
  • Java實(shí)現(xiàn)簡(jiǎn)單的貪吃蛇小游戲

    Java實(shí)現(xiàn)簡(jiǎn)單的貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單的貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Java獲得當(dāng)前時(shí)間前指定幾個(gè)小時(shí)具體時(shí)間的方法示例

    Java獲得當(dāng)前時(shí)間前指定幾個(gè)小時(shí)具體時(shí)間的方法示例

    這篇文章主要介紹了Java獲得當(dāng)前時(shí)間前指定幾個(gè)小時(shí)具體時(shí)間的方法,涉及java使用Calendar針對(duì)日期時(shí)間的相關(guān)運(yùn)算與轉(zhuǎn)換操作技巧,需要的朋友可以參考下
    2017-08-08
  • java 根據(jù)身份證號(hào)碼判斷出生日期、性別、年齡的示例

    java 根據(jù)身份證號(hào)碼判斷出生日期、性別、年齡的示例

    這篇文章主要介紹了java 根據(jù)身份證號(hào)碼判斷出生日期、性別、年齡的示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-10-10
  • Java使用POI-TL和JFreeChart動(dòng)態(tài)生成Word報(bào)告

    Java使用POI-TL和JFreeChart動(dòng)態(tài)生成Word報(bào)告

    本文介紹了使用POI-TL和JFreeChart生成包含動(dòng)態(tài)數(shù)據(jù)和圖表的Word報(bào)告的方法,并分享了實(shí)際開發(fā)中的踩坑經(jīng)驗(yàn),通過(guò)代碼示例講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2025-02-02
  • 如何獲得spring代理對(duì)象的原對(duì)象

    如何獲得spring代理對(duì)象的原對(duì)象

    這篇文章主要介紹了如何獲得spring代理對(duì)象的原對(duì)象的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • MybatisPlus代碼生成器使用示例

    MybatisPlus代碼生成器使用示例

    MyBatis-Plus自動(dòng)化的生成與數(shù)據(jù)庫(kù)表對(duì)應(yīng)的Java代碼文件,本文主要介紹了MybatisPlus代碼生成器使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-06-06
  • Java中List集合數(shù)據(jù)修改方式

    Java中List集合數(shù)據(jù)修改方式

    這篇文章主要介紹了Java中List集合數(shù)據(jù)修改方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java中Redis的布隆過(guò)濾器詳解

    Java中Redis的布隆過(guò)濾器詳解

    這篇文章主要介紹了Java中Redis的布隆過(guò)濾器詳解,我們經(jīng)常會(huì)把一部分?jǐn)?shù)據(jù)放在Redis等緩存,比如產(chǎn)品詳情,這樣有查詢請(qǐng)求進(jìn)來(lái),我們可以根據(jù)產(chǎn)品Id直接去緩存中取數(shù)據(jù),而不用讀取數(shù)據(jù)庫(kù),這是提升性能最簡(jiǎn)單,最普遍,也是最有效的做法,需要的朋友可以參考下
    2023-09-09

最新評(píng)論

科技| 宜昌市| 夹江县| 平原县| 四会市| 元谋县| 贵州省| 闻喜县| 陇川县| 从化市| 酉阳| 洮南市| 宜兰市| 博野县| 乌鲁木齐市| 剑河县| 道真| 河西区| 田林县| 宜宾县| 涞水县| 兴宁市| 徐闻县| 卓资县| 罗定市| 桐梓县| 西平县| 绥中县| 恩施市| 呼图壁县| 休宁县| 吉木乃县| 吐鲁番市| 防城港市| 贵溪市| 五常市| 天柱县| 旌德县| 梅河口市| 淳化县| 萨迦县|