【工作记录】JDBC连接MySQL,跨时区调查CST转Asia/Shangha

根据业务要求,不同的国家设置jvm参数,来确定当前时区。

// -Duser.timezone=Asia/Kolkata 印度加尔各答 GMT+05:30
// -Duser.timezone=Asia/Bangkok 泰国曼谷     GMT+07:00
// -Duser.timezone=Asia/Shangha 中国上海     GMT+08:00

由于各个国家上线项目不完全相同,部分功能在不同的项目有不同实现方式。数据同步时,发生了跨时区同步数据的情况。
例如:
在某个国家部署A服务,在当地时间执行同步任务,可以同步到正确的业务数据,其中业务数据类型使用java.util.Date。
另一个国家部署B服务,同样业务数据类型使用java.util.Date,在当地时间执行同步任务,不可以同步到正确的业务数据,只好改写为java.lang.String类型。
调查原因,发现B服务的jdbc的jar包版本太低,不支持自动时区转换,升级版本为6.0.3,可以正确同步数据。

  • JdbcTimestampValueFactory
    public Timestamp createFromTimestamp(int year, int month, int day, int hours, int minutes, int seconds, int nanos) {
        if (year == 0 && month == 0 && day == 0) {
            throw new DataReadException(Messages.getString("ResultSet.InvalidZeroDate"));
        } else {
            synchronized(this.cal) {
                this.cal.set(year, month - 1, day, hours, minutes, seconds);
                Timestamp ts = new Timestamp(this.cal.getTimeInMillis());
                ts.setNanos(nanos);
                return ts;
            }
        }
    }

但同时发现A服务不需要指定jdbc.url中的serverTimezone=Asia/Shanghai。

跟踪代码MysqlaSession.configureTimezone(),在不指定serverTimezone时,跟踪获取数据库服务器的时区的代码,获取的确实为CST,但在将转换为对应时区时,A服务将CST转为了Asia/Shanghai,但B服务仍然为CST=Asia/Kolkata。

  • MysqlaSession
    public void configureTimezone() {
        String configuredTimeZoneOnServer = this.getServerVariable("time_zone");
        if ("SYSTEM".equalsIgnoreCase(configuredTimeZoneOnServer)) {
            configuredTimeZoneOnServer = this.getServerVariable("system_time_zone");
        }

        String canonicalTimezone = (String)this.getPropertySet().getStringReadableProperty("serverTimezone").getValue();
        if (configuredTimeZoneOnServer != null && (canonicalTimezone == null || StringUtils.isEmptyOrWhitespaceOnly(canonicalTimezone))) {
            try {
                canonicalTimezone = TimeUtil.getCanonicalTimezone(configuredTimeZoneOnServer, this.getExceptionInterceptor());
            } catch (IllegalArgumentException var4) {
                throw (WrongArgumentException)ExceptionFactory.createException(WrongArgumentException.class, var4.getMessage(), this.getExceptionInterceptor());
            }
        }

        if (canonicalTimezone != null && canonicalTimezone.length() > 0) {
            this.serverTimezoneTZ = TimeZone.getTimeZone(canonicalTimezone);
            if (!canonicalTimezone.equalsIgnoreCase("GMT") && this.serverTimezoneTZ.getID().equals("GMT")) {
                throw (WrongArgumentException)ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("Connection.9", new Object[]{canonicalTimezone}), this.getExceptionInterceptor());
            }
        }

        this.defaultTimeZone = this.serverTimezoneTZ;
    }

继续跟进转换代码,在com.mysql.cj.jdbc.util.TimeUtil#loadTimeZoneMappings()中,会加载/com/mysql/cj/jdbc/util/TimeZoneMapping.properties文件,在A服务的资源文件中,有个TimeZoneMapping.properties,并且包含 CST=Asia/Shanghai。Git代码提交记录备注为 CST TimeZone point to Asia/Shanghai

  • TimeUtil
    private static void loadTimeZoneMappings(ExceptionInterceptor exceptionInterceptor) {
        timeZoneMappings = new Properties();

        try {
            timeZoneMappings.load(TimeUtil.class.getResourceAsStream("/com/mysql/cj/jdbc/util/TimeZoneMapping.properties"));
        } catch (IOException var5) {
            throw ExceptionFactory.createException(Messages.getString("TimeUtil.LoadTimeZoneMappingError"), exceptionInterceptor);
        }

        String[] var1 = TimeZone.getAvailableIDs();
        int var2 = var1.length;

        for(int var3 = 0; var3 < var2; ++var3) {
            String tz = var1[var3];
            if (!timeZoneMappings.containsKey(tz)) {
                timeZoneMappings.put(tz, tz);
            }
        }

    }

&#x91CD;&#x8981;&#x53C2;&#x8003;&#x94FE;&#x63A5;&#xFF1A;
- https://www.cnblogs.com/sogeisetsu/p/12324161.html
- https://blog.csdn.net/weixin_37015554/article/details/105198428
- https://blog.csdn.net/weixin_41917635/article/details/103719481

Original: https://www.cnblogs.com/Candies/p/14121729.html
Author: Candyメ奶糖
Title: 【工作记录】JDBC连接MySQL,跨时区调查CST转Asia/Shangha

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/574321/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 关于Mysql触发器

    关于:after触发器—是在记录操纵之后触发,是先完成数据的增删改,再触发,触发的语句晚于监视的增删改操作,无法影响前面的增删改动作before触发器—是在记录操纵之前触发,是先完…

    Java 2023年6月13日
    077
  • cpp和c中struct用法的区别

    cpp和c中struct用法的区别 不使用typedef C语言中,定义struct的语法如下: struct [<tag>] { <member-list&gt…

    Java 2023年6月7日
    072
  • Unity-2D

    Unity-2D 1.Unity中的2D模式: 1)游戏在二维上展示 启用 2D 模式时将会设置正交(即无透视)视图:摄像机沿 Z 轴观察,而 Y 轴向上增加。因此可以轻松可视化场…

    Java 2023年6月13日
    068
  • Redisson多策略注解限流

    限流:使用Redisson的RRateLimiter进行限流 多策略:map+函数式接口优化if判断 限流:使用Redisson的RRateLimiter进行限流 多策略:map+…

    Java 2023年6月7日
    078
  • Servlet 学习总结

    Servlet学习笔记 Servlet学习 学习视频为:https://www.bilibili.com/video/BV1Ta4y1H7Vc IDEA的使用 IDEA的简介 ID…

    Java 2023年6月14日
    065
  • @JSONField @JsonFormat @JsonProperty 使用场景

    1.@JSONField 是com.alibaba.fastjson.annotation包下的 主要作用是在序列化/反序列化时控制key的名称, @JSONField(name …

    Java 2023年6月5日
    065
  • MySQL七:一文详解六大日志

    转载~ 日志一般分为逻辑日志与物理日志两类 「逻辑日志」:即执行过的事务中的sql语句,执行的sql语句(增删改) 「反向」的信息 「物理日志」: mysql 数据最终是保存在数据…

    Java 2023年6月8日
    094
  • Java 基础(方法引用 Method References)

    当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! 方去引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口…

    Java 2023年5月29日
    075
  • MySQL学习-下载jar包

    https://blog.csdn.net/Milan__Kundera/article/details/81182757 这个链接复制到浏览器查看 Original: https…

    Java 2023年6月9日
    040
  • 分布式搜索引擎–03

    1.数据聚合 聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如: 什么品牌的手机最受欢迎? 这些手机的平均价格、最高价格、最低价格? 这些手机…

    Java 2023年6月9日
    068
  • Spring(三)——AOP

    (1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。(2)通俗描述:不通过…

    Java 2023年6月16日
    059
  • fastposter v2.7.1 紧急发布 电商海报编辑器

    fastposter v2.7.1 紧急发布 电商海报编辑器 fastposter海报生成器,电商海报编辑器,电商海报设计器,fast快速生成海报 海报制作 海报开发。二维码海报,…

    Java 2023年6月5日
    080
  • 从零开始实现放置游戏(十五)——实现战斗挂机(6)在线打怪练级

    本章初步实现游戏的核心功能——战斗逻辑。 战斗系统牵涉的范围非常广,比如前期人物的属性、怪物的配置等,都是在为战斗做铺垫。 战斗中,人物可以施放魔法、技能,需要技能系统支持。 战斗…

    Java 2023年6月5日
    071
  • 【RocketMQ】重试

    一. 消息发送重试 生产者在发送消息时,同步消息失败会重投,异步消息有重试,oneway没有任何保证。消息重投保证消息尽可能发送成功、不丢失,但可能会造成消息重复发送。消息重复发送…

    Java 2023年5月29日
    061
  • springboot-jta-atomikos多数据源事务管理

    背景 我们平时在用springboot开发时,要使用事务,只需要在方法上添加@Transaction注解即可,但这种方式只适用单数据源,在多数据源下就不再适用; 比如在多数据源下,…

    Java 2023年6月7日
    065
  • Java使用 Thumbnails 压缩图片

    业务:用户上传一张图片到文件站,需要返回原图url和缩略图url 处理思路: 因为上传图片方法返回url是单个上传,第一步先上传原图并返回url 处理缩略图并上传:拿到Multip…

    Java 2023年6月9日
    084
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球