【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换

2023-06-30 371 0

引言

【JVM时区配置-两行代码让我们一帮子人熬了一个通宵】描述了由于代码BUG导致存储到数据库的时间比正常时间少八小时的案例。案例中对于数据库字段类型是datetime和timestamp的时区转换关系进行了描述,本文试图从代码角度描述以下逻辑:

  • JDBC场景下MySQL Session时区如何配置的
  • JDBC场景下datetime类型的数据如何转换的

测试环境 MySQL

配置项 说明
MySQL version Windows MySQL Server 8.0.30.0
time_zone +08:00
system_time_zone
创建测试库 create database test;
创建测试表 create table datetimetest( dt datetime);

应用信息

java version "1.8.0_341"Java(TM) SE Runtime Environment (build 1.8.0_341-b10)Java HotSpot(TM) Client VM (build 25.341-b10, mixed mode, sharing)复制

pom

<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version></dependency>复制

分析过程 测试场景

  • JVM是UTC + 8,MySQL time_zone是UTC + 8,MySQL JDBC Driver配置的是UTC + 0
  • JVM 应用程序原始时间是(UTC + 8):2022-10-16 10:00:00
  • MySQL JDBC Driver发送给MySQL server的时间是:2022-10-16 02:00:00(时间由UTC + 8转换为UTC + 0)
  • MySQL server最终存储的时间为:2022-10-16 02:00:00
  • MySQL JDBC Driver从数据库中查出的时间是:2022-10-16 02:00:00
  • 应用程序最终读取到的时间是:2022-10-16 10:00:00

测试代码

【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换

getConnection

【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换
从图中看创建一个数据库连接是个非常重量级的操作,选择一个高效的连接池很重要。与本篇文章主要相关的是图中斜体红色加粗部分。

关注点一

关注跟time_zone相关的几个配置项。
相关类及配置说明文件:PropertyDefinitions、LocalizedErrorMessages.properties。

配置项 默认值 sinceVersion
connectionTimeZone 字符串类型,默认值:null 3.0.2
forceConnectionTimeZoneToSession 布尔类型,默认值:false 8.0.23
preserveInstants 布尔类型,默认值:true 8.0.23

关注点二

【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换

executeUpdate

PreparedStatement的实现类是:com.mysql.cj.jdbc.ClientPreparedStatement,跟本次文章相关的内容如下:

编码器

在NativeProtocol类初始化的时候会将不同数据类型的编码器注册&初始化:

static Map<Class<?>, Supplier<ValueEncoder>> DEFAULT_ENCODERS = new HashMap<>();static { DEFAULT_ENCODERS.put(BigDecimal.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(BigInteger.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(Blob.class, BlobValueEncoder::new); DEFAULT_ENCODERS.put(Boolean.class, BooleanValueEncoder::new); DEFAULT_ENCODERS.put(Byte.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(byte[].class, ByteArrayValueEncoder::new); DEFAULT_ENCODERS.put(Calendar.class, UtilCalendarValueEncoder::new); DEFAULT_ENCODERS.put(Clob.class, ClobValueEncoder::new); DEFAULT_ENCODERS.put(Date.class, SqlDateValueEncoder::new); DEFAULT_ENCODERS.put(java.util.Date.class, UtilDateValueEncoder::new); DEFAULT_ENCODERS.put(Double.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(Duration.class, DurationValueEncoder::new); DEFAULT_ENCODERS.put(Float.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(InputStream.class, InputStreamValueEncoder::new); DEFAULT_ENCODERS.put(Instant.class, InstantValueEncoder::new); DEFAULT_ENCODERS.put(Integer.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(LocalDate.class, LocalDateValueEncoder::new); DEFAULT_ENCODERS.put(LocalDateTime.class, LocalDateTimeValueEncoder::new); DEFAULT_ENCODERS.put(LocalTime.class, LocalTimeValueEncoder::new); DEFAULT_ENCODERS.put(Long.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(OffsetDateTime.class, OffsetDateTimeValueEncoder::new); DEFAULT_ENCODERS.put(OffsetTime.class, OffsetTimeValueEncoder::new); DEFAULT_ENCODERS.put(Reader.class, ReaderValueEncoder::new); DEFAULT_ENCODERS.put(Short.class, NumberValueEncoder::new); DEFAULT_ENCODERS.put(String.class, StringValueEncoder::new); DEFAULT_ENCODERS.put(Time.class, SqlTimeValueEncoder::new); DEFAULT_ENCODERS.put(Timestamp.class, SqlTimestampValueEncoder::new); DEFAULT_ENCODERS.put(ZonedDateTime.class, ZonedDateTimeValueEncoder::new);}复制

与datetime相关的是SqlTimestampValueEncoder

SqlTimestampValueEncoder

【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换

getTimestamp

ResultSet的实现类是:com.mysql.cj.jdbc.result.ResultSetImpl,getTimestamp主要涉及两部分:

  • MysqlTextValueDecoder将原始报文字段解析为InternalTimestamp对象
  • SqlTimestampValueFactory将InternalTimestamp对象解析为应用使用的Timestamp

MysqlTextValueDecoder

【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换

SqlTimestampValueFactory

【全网首发】TimeZone-datetime在JVM时区和MySQL Session时区的转换

相关文章

Switch怎样限制孩子下载的游戏类型
如何批量修改Word文档正文字体格式
win10设置新密码总是不符合
如何解决win10系统开机速度慢问题
win10休眠在哪里
win10如何更**辨率?