当前位置: 首页 > 网络应用技术

数据库时间慢了14小时,Mybatis说,我不携带这个锅!

时间:2023-03-07 17:30:59 网络应用技术

  同事反馈一个问题:Mybatis昨天插入数据库,是因为Mybatis反向工程生成的代码存在问题吗?

  每个人都知道我对这种类型的错误非常感兴趣。intuition告诉我,这不应该是mybatis的错误,这很可能是时区。

  非常好,今天您可以带所有人检查错误,看看您可以从此错误检查中获得哪些技能。

  这项研究的问题有点深,但是结论很重要。

  当同事反馈时,我带来了自己的猜想:这是由设置的数据库字段引起的吗?是由Mybatis反向工程生成的代码不一致引起的吗?

  同事们还需要将DateTime更改为Varchar ...我立即被我拦住,说:首先检查问题,然后谈论解决方案,我还花时间在下午看。

  第一步是检查数据库字段类型,是的,没问题。

  第二步是检查物理类的类型,这是一种类型,没有问题。

  第三步,错误复制。

  在错误的此步骤中,使用了单元测试。我以前与我的朋友讨论了单位测试的魅力,现在我越来越像单位测试。

  该项目基于Spring Boot,单元测试如下(代码已脱敏):

  执行单元测试并检查数据库中插入的数据。布格重新出现,时间确实是前一天,从当前时间起14小时。

  在上述三个步骤调查之后,验证了数据库字段和代码的类型。单元测试还重现了问题。我的同事没有欺骗我。他们总是必须看到,哈哈?

  因此,基本上确定为时区。

  检查服务器时间登录到测试服务器,执行日期命令,检查服务器时间和时区域:

  显示时间是当前时间,使用CST时间,最后一个+0800,East 8区,没问题。

  检查数据库时区连接数据库并执行Show命令:

  system_time_zone:全局参数,系统时区,检查MySQL启动并根据系统时区设置全局参数System_zone的值并设置当前系统时区。该值是CST,它与系统时间的时区是一致的。。

  time_zone:全局参数,设置每个连接会话的时区,默认为全局参数system_time_zone的值。

  检查中间时区时时区的代码以添加打印时区的代码:

  打印时区是:

  换句话说,Java使用UTC时区进行业务逻辑,这也是东八区的时间。

  那么问题在哪里?

  在上述研究之后,基本上确定为时区问题。在这里,添加上述相关的时区知识点。

  UTC时间UTC时间:世界协调时间(UTC)是世界上不同国家 /地区使用的主要时间标准,即调节时钟和时间,即零时间区域的时间。

  UTC,协调的通用时间是标准,而不是时区。UTC是全球时间标准。世界上所有人都同意同步协调(协调),这也是UTC名称的来源:通用协调时间。

  CST时间CST时间:中央标准时间。

  CST可以代表以下4个不同时区:

  显然,很明显,它与UTC时间无关,这只是时间标准。目前,MySQL中的System_time_zone是CST,CST可以代表4个不同的时区。那么,MySQL对此进行了哪个时区?

  简单地计算,中国时间是UT+8:00,美国是UT-6:00。当它在中国引入时,它直接转换为美国时间(不考虑时区问题),时间为14小时。

  现在您知道了问题,解决方案将可用。

  可以通过数据库级别和代码级别解决上述问题。

  由于MySQL了解CST指定的时区,因此将其设置为右侧。

  连接MySQL数据库并设置正确的时区:

  再次执行show命令:

  可以看出,时区已成为东八区的时间。再次执行单位测试,并解决了问题。

  该方案还可以直接修改指定时区的mysql my.cnf文件。

  当代码连接到数据库时,请指定参数使用的时区。

  在连接到配置数据库的URL后面添加指定的时区:

  再次执行单元测试后,也可以解决问题。

  在上述分析和操作之后,解决了时区的问题。问题是这样结束的吗?为什么这样?

  为了验证时区问题,在数据库中创建了一个在时区错误的字段。此字段类型是DateTime,默认值为Current_Timestamp。

  因此,此时插入记录以使MySQL自动生成该字段的时间。您什么时候猜到这个领域?中国时间。

  魔术?为什么CST时区,系统会自动生成合适的时间,而代码插入的时间有时会不同?

  MySQL是否将CST时区理解为美国时代,还是将泳池或驾驶员连接的Mybatis理解为美国时间?

  为了遵循代码中存在问题的问题,首先打开MyBatis调试日志,以查看插入时值什么值:

  以上是插入时的参数,这意味着在mybatis级别上没有问题。

  这是连接池还是驱动程序的问题?根据连接池本身,与数据库的特定操作关系不是很好,因此我直接检查驱动程序。

  Mybatis是XML中固定日期字段的类型。在拾取MySQL-Connector-Java-8.0.x的源代码后,发现它被用于处理类型。

  在构造函数上播放断点并执行单元测试:

  可以清楚地看出,日历将时区设置为locale.us,即美国时间,时区为CST,主机为-21600,000. -21600,000单位,是毫秒,它们被转换为小时。它恰好是“ -6:00”,从北京时间开始仅14小时“ GMT+08:00”。

  因此,一直到最终呼叫链接。TimeZone来自NativeServersession的ServertimeZone,Serverzone的值是由本机关系类别的ConfigureTimeZone方法设置的。

  调试跟踪上述代码,显示信息如下:

  此时,通过获取CanonicalTimeZone值,我们可以看到URL背后的配置的作用。它们在它们后面,第一个代码块获得了time_zone的值,以及在第二个代码块中system_time_zone的值。与查询数据库获得的值一致。

  因为有问题时URL中没有参数,所以典型的时区为null.Logutil.getCanonical TimeZone方法:称为:

  在上面的代码中,我终于走到了LoadTimeZoneMappings(exceptionInterceptor);方法:方法:

  此方法将值加载在配置文件“/com/mysql/cj/util/timezonempapping.properties”中。转换后,在TimeZoneMappings中,CST为“ CST”。

  最后,Canonical TimeZone为“ CST”,而TimeZone是由TimeZone.GetTimeZone(Canonical TimeZone)获得的。

  换句话说,TimeZone.getTimeZone(“ CST”)的值是美国时间。编写单元测试以验证:

  打印结果:

  显然,在将此方法传递到CST之后,默认值为美国时间。

  在这一点上,问题的原因基本上很清楚:

  再次扩展,server_time_zone和time_zone均来自AntiveServersession的ServerVariables变量。该变量是在原住民的负载方法中初始化的。

  在上述StringBuilder的附加操作中,有“ @@ time_zone为time_zone”和“ @@@@@ system_time_zone as system_time_zone”,然后查询数据库。获取数据库值后,将其放在Sercarables上。

  让我们再次调试:

  可以看出,system_time_zone的值是CST。

  同一time_zone的值是“系统”。

  根据代码中的提示,缝合与代码相同的代码的数据库:

  该值确实是“系统”。这次,我们还提出了另一种查询MySQL当前时区的方法。

  在这一点上,对这个问题的调查已经完美结束。呼吸~~~

  在检查上述问题的过程中,使用单位测试多次使用。这也是单位测试的魅力。使用最简单的代码,最轻的逻辑和最多的时间来验证和跟踪错误。

  回顾上述错误调查中使用和学习的知识点:

  您通过在此错误中发现的文章学到了什么?如果您有一点灵感,请不要尴尬,请给予赞美!

  博客作者简介:“ Springboot Technology Inner Book”技术书籍作者,喜欢学习技术,撰写技术干货文章。

  公共帐户:博客作者的公共帐户“计划的新愿景”,欢迎关注?

  技术交流:请联系博客微信:Zhuan2quan