闲来无事,看一看 java8 新的时间API和mybatis怎么结合使用,于是就谢了个小demo尝试,没想到发生了“由时区问题引起的血案”。
- 环境
- 本人电脑 MacBook Pro (15-inch, 2016) ,java version "1.8.0_131"
- 项目使用 Spring4.3.8+java8+mybatis3.4.4 搭建
- 数据库 使用kvm虚机搭建MariaDB-10.1.14
- 代码
public class TestLocalDate {
private Date birthday;
private LocalDate localDate;
private LocalTime localTime;
private LocalDateTime localDateTime;
// 省略set get
}
<resultMap id="BaseMap" type="com.github.mmall.pojo.TestLocalDate">
<result property="birthday" column="birthday"/>
<result property="localDate" column="local_date"/>
<result property="localTime" column="local_time"/>
<result property="localDateTime" column="local_date_time"/>
</resultMap>
<select id="getTestLocalDate" resultMap="BaseMap">
SELECT * FROM test_localdate
</select>
测试代码
@Test
public void testLocalDateService() {
TimeZone aDefault = TimeZone.getDefault();
System.out.println(aDefault.getDisplayName());
List<TestLocalDate> localDate = localDateService.getLocalDate();
TestLocalDate testLocalDate = localDate.get(0);
System.out.println(testLocalDate);
}
- 结果
TestLocalDate{birthday=Thu Aug 10 02:32:50 CST 2017, localDate=2017-08-09, localTime=13:32:50, localDateTime=2017-08-09T13:32:50}
- 发生了什么 查询本机,数据库服务器,数据库的时区
# 本机
# gx @ gxdemacbook-pro in ~ [10:22:26]
$ date
2017年 8月 9日 星期三 10时22分28秒 CST
# gx @ gxdemacbook-pro in ~ [10:22:28]
$ date -R
Wed, 09 Aug 2017 10:35:31 +0800
# 数据库服务器
[root@kvm-010834 ~]# date
Wed Aug 9 14:47:13 CST 2017
[root@kvm-010834 ~]# date -R
Wed, 09 Aug 2017 14:47:17 +0800
# 数据库
MariaDB [mmall]> show variables like "%time_zone%";
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)
MariaDB [mmall]> select now();
+---------------------+
| now() |
+---------------------+
| 2017-08-09 14:48:54 |
+---------------------+
1 row in set (0.00 sec)
至此也没有发现什么不一样呀,为什么java 查出的时间会有差异呢?接下来直接上driver模式,去掉mybatis
@Test
public void testJDBC() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://9.111.111.193:3306/mmall", "root", "passw0rd");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select birthday from test_localdate");
while (resultSet.next()) {
Timestamp birthday = resultSet.getTimestamp("birthday");
System.out.println("Timestamp : "+birthday);
Date birthday1 =
resultSet.getDate("birthday");
Time birthday2 = resultSet.getTime("birthday");
System.out.println("Date : "+birthday1);
System.out.println("Time : "+birthday2);
String time =resultSet.getString("birthday");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("String : " +time);
System.out.println(sdf.parse(time));
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
发现结果没有变化,只有resultSet.getString("birthday"); 作为 字符串返回时候才和数据库显示相同,使用时间函数返回的结果都不正确。 应该还是数据库的原因。查询my.cnf也没有配置zone相关的信息,自认为使用和服务器应该一样。但是
进入mysql command
MariaDB [mmall]> set global time_zone = '+8:00';
然后在返回执行,奇迹出现了。结果正确。
- 记录
安装服务器的时候一定要配置 my.cnf 添加 default-time_zone = '+8:00',设置时区;
select now();语句是服务器的时间;
CST可以为如下4个不同的时区的缩写: 美国中部时间:Central Standard Time (USA) UT-6:00 澳大利亚中部时间:Central Standard Time (Australia) UT+9:30 中国标准时间:China Standard Time UT+8:00 古巴标准时间:Cuba Standard Time UT-4:00 数据库show variables like "%time_zone%";语句并不能保证时区正确。
- mybatis+ java8
添加依赖,即可,
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>
看到其他bolg有写到 这种方式只对3.4以上mybatis生效。 若版本小于3.4,则需手动添加 typeHandler
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.InstantTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalDateTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.LocalTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.OffsetDateTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.OffsetTimeTypeHandler" />
<typeHandler handler="org.apache.ibatis.type.ZonedDateTimeTypeHandler" />
</typeHandlers>