“夏令时”的版本间的差异
跳到导航
跳到搜索
Jihongchang(讨论 | 贡献) |
Jihongchang(讨论 | 贡献) |
||
第55行: | 第55行: | ||
--> | --> | ||
</syntaxhighlight>如果把驱动包换成 8.0.21就不会抛异常 | </syntaxhighlight>如果把驱动包换成 8.0.21就不会抛异常 | ||
+ | |||
+ | |||
+ | 8.0.21 后的版本实现都会因为 java.util.Date birthDate 的属性声明,把 birthDate 当成一个 Timestamp 解析:<syntaxhighlight lang="java"> | ||
+ | package com.mysql.cj.result; | ||
+ | |||
+ | public class SqlTimestampValueFactory extends AbstractDateTimeValueFactory<Timestamp> { | ||
+ | |||
+ | @Override | ||
+ | public Timestamp localCreateFromDate(InternalDate idate) { | ||
+ | if (idate.getYear() == 0 && idate.getMonth() == 0 && idate.getDay() == 0) { | ||
+ | throw new DataReadException(Messages.getString("ResultSet.InvalidZeroDate")); | ||
+ | } | ||
+ | |||
+ | synchronized (this.defaultTimeZone) { | ||
+ | Calendar c; | ||
+ | |||
+ | if (this.cal != null) { | ||
+ | c = this.cal; | ||
+ | } else { | ||
+ | // c.f. Bug#11540 for details on locale | ||
+ | c = Calendar.getInstance(this.defaultTimeZone, Locale.US); | ||
+ | c.setLenient(false); | ||
+ | } | ||
+ | |||
+ | try { | ||
+ | c.clear(); | ||
+ | c.set(idate.getYear(), idate.getMonth() - 1, idate.getDay(), 0, 0, 0); | ||
+ | return new Timestamp(c.getTimeInMillis()); | ||
+ | } catch (IllegalArgumentException e) { | ||
+ | throw ExceptionFactory.createException(WrongArgumentException.class, e.getMessage(), e); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
=== 1941-03-15 00:00 不存在 === | === 1941-03-15 00:00 不存在 === |
2025年8月19日 (二) 02:23的版本
一次生产环境遇到的问题
现象是程序运行过程中查询用户的数据抛异常:
java.lang.IllegalArgumentException: HOUR_OF_DAY: 0 -> 1
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2829)
at java.util.Calendar.updateTime(Calendar.java:3395)
at java.util.Calendar.getTimeInMillis(Calendar.java:1782)
进一步定位发现只要查询一条出生日期是 1941-03-15 的数据,程序就会抛这个异常,但查别的数据都没有问题
具体的实现是
表 user 中有一个 date 类型的字段 birth_date,用来存储用户的出生年月日,
对应 Java 代码中的 User 类中声明的 java.util.Date 类型的 birthDate,然后应用了 Mybatis 执行查询,
对应的 mapper 映射文件是:
……
<resultMap type="User" id="UserResult">
……
<result property="birthDate" column="birth_date">
……
</resultMap>
……
<select id="selectUserList" resultMap="UserResult">
select * from user
</select>
……
大概就是上面这样
pom.xml 文件中
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
<!--
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
-->
如果把驱动包换成 8.0.21就不会抛异常
8.0.21 后的版本实现都会因为 java.util.Date birthDate 的属性声明,把 birthDate 当成一个 Timestamp 解析:
package com.mysql.cj.result;
public class SqlTimestampValueFactory extends AbstractDateTimeValueFactory<Timestamp> {
@Override
public Timestamp localCreateFromDate(InternalDate idate) {
if (idate.getYear() == 0 && idate.getMonth() == 0 && idate.getDay() == 0) {
throw new DataReadException(Messages.getString("ResultSet.InvalidZeroDate"));
}
synchronized (this.defaultTimeZone) {
Calendar c;
if (this.cal != null) {
c = this.cal;
} else {
// c.f. Bug#11540 for details on locale
c = Calendar.getInstance(this.defaultTimeZone, Locale.US);
c.setLenient(false);
}
try {
c.clear();
c.set(idate.getYear(), idate.getMonth() - 1, idate.getDay(), 0, 0, 0);
return new Timestamp(c.getTimeInMillis());
} catch (IllegalArgumentException e) {
throw ExceptionFactory.createException(WrongArgumentException.class, e.getMessage(), e);
}
}
}
}
1941-03-15 00:00 不存在
MySQL 中的 date 类型
MySQL 中的 date 类型只存年月日
Java 中的 java.util.Date 和 java.sql.Date