加入收藏 | 设为首页 |

辣木籽-一个MySQL时刻戳精度引发的血案

海外新闻 时间: 浏览:285 次

作者: 阿杜的国际 javaadu

写在前面

最近工作中遇到两例mysql时刻戳相关的问题,一个是mysql-connector-java和msyql的精度不一致导致数据查不到;另一例是运用服务器时区过错导致数据查询不到。

通过这篇文章,期望能够回答关于mysql中时刻戳的几个问题:

  1. mysql中的DATETIME精度为什么只支撑到秒?
  2. mysql中的DATETIME类型跟时区有关吗?
  3. mysql规划表的时分,表明时刻的字段改怎样挑选?

事例剖析:DATETIME的精度问题

前段时刻,将担任的运用的mysql-connector-java的版别从5.1.16升级到5.1.30,在做功用回归的时分发现,运用了相似上面的SQL的用例的运转时数据会有遗失,导致功用有问题。

考虑到我担任的运用中,有个功用需求用到相似下面这种SQL,即运用时刻戳作为查询的条件,查询在某个时刻戳之后的一切数据。

通过排查发现:mysql-connector-java在5.1.23之前会将秒后边的精度丢掉再传给MySQL服务端,正好咱们运用的mysql版别中DATETIME的精度是秒;在我将mysql-connector-java升级到5.1.30后,从java运用通过mysql-connector-java将时刻戳传到MySQL服务端的时分,就不会将毫秒数丢掉了,从mysql-connector-java的视点看是修正了一个BUG,可是关于我的运用来说却是触发了一个BUG。

假如你面临这个问题,你会怎样修正呢?

咱们其时想了三种计划:

  • 将mybatis的Mapper接口中的时刻戳参数的类型,从java.util.Date改成java.sql.Date;
  • 在传入Mapper接口之前,将传入的时刻戳按秒取正,代码如下

  • 在查询之前辣木籽-一个MySQL时刻戳精度引发的血案,将传入的时刻戳减1秒;

通过验证,计划1会,java.util.Date转过去的java.sql.Date目标会将日期之后的精度悉数丢掉,然后导致查询出更多不必要的数据;计划3是能够的,便是可能会查出多一两条数据;计划2也是能够的,相当于从代辣木籽-一个MySQL时刻戳精度引发的血案码上对mysql-connector-java的特性做了补偿。终究我挑选的是计划2。

事例复现

运用homebrew装置MySQL,版别是8.0.15,装好后建一个表,用来寄存用户信息,SQL如下:

运用spirngboot + mybatis作为开发结构,界说一个用户实体,代码如下所示:

界说该实体对应的Mapper,代码如下:

设置衔接mysql相关的装备,代码如下:

编写测验代码,先刺进一条数据,然后用时刻戳作为查询条件去查询,代码如下:

运转单测,如咱们的想象,确实是没有查询出数据来,成果如下:

然后修正代码,运用上面的代码将查询的时刻戳按秒取正,代码如下:

再次运转单测,如咱们的想象,这次能够查询出数据来了。

不过,这儿有个小插曲,我在最开端规划表的时分,运用的SQL句子是下面这样的:

你必定发现了,这儿的datetime现已支撑小数点后更小的时刻精度了,最多支撑6位即最多能够支撑到奇妙等级。辣木籽-一个MySQL时刻戳精度引发的血案这个特性是什么时分引进的呢,我去查阅了MySQL的官方文档(https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html),发现这个特性是在mysql 5.6.4之后开端支撑的。

知识点总结

通过了前面的辣木籽-一个MySQL时刻戳精度引发的血案实践事例剖析和事例复现,想孟阳直播间必读者现已对mysql中DATETIME这个类型有了必定的知道,接下来跟我一同看下,咱们从这个事例中能够总结出哪些经历。

  1. mysql-connector-java的版别和mysql的版别需求配套运用,例如5.6.4之前的版别,就最好不要运用mysql-connector-java的5.1.23之后的版别,不然就可能会遇到咱们这次遇到的问题。
  2. MySQL中用来表明时刻的字段类型有:DATE、DATETIME、TIMESTAMP,它们之间有相同点,各自也有自己的特性,我总结了一个表格,如下所示:

  1. DATETIME类型在MySQL中是以“YYYYMMDDHHMMSS”格局的整数寄存的,与时区无关,运用8个字节的空间;
  2. TIMESTAMP类型能够保存的时刻规模要小许多,显现的值依靠时区,MySQL的服务器、操作系统以及客户端衔接都有时区的设置。
  3. 一般情况下引荐运用DATETIME作为时刻戳字段,不引荐运用bigint类型来存储时刻。
  4. 在开发中,应该尽量防止运用时刻戳作为查询条件,假如有必要要用,则需求充分考虑MySQL的精度和查询参数的精度等问题。