MyBatis + MyBatis CDI + PostgreSQL的时区问题

时间:2017-10-18 17:39:30

标签: java postgresql mybatis ibatis mybatis-cdi

我在MyBatis中遇到了一个奇怪的时区问题。

环境:

  • mybatis v3.4.5
  • mybatis-cdi v1.0.1
  • Payara app Server v4.1.2.173
  • PostgreSQL数据库
  • JNDI数据源,MANAGED交易设置

首先我将记录插入到有日期时间字段的表中。 在Java方面,它是java.time.ZonedDateTime。在数据库中,我对此字段使用TIMESTAMP WITH TIME ZONE

这是相关的代码:

request.setRequestDate = ZonedDateTime.now();
LOGGER.info("xxx-xxx-xxx: " + httpRequest.getRequestDate());
myMapper.save(request);

在日志文件中,我可以看到:

[INFO ] 2017-10-18 18:43:45,501 com..................... - xxx-xxx-xxx: 2017-10-18T18:43:45.493+02:00[Europe/Prague]
[DEBUG] 2017-10-18 18:43:45,608 com...xxxDao.saveRequest - ==>  Preparing: INSERT INTO table_a (id, ..., request_date) VALUES (?, ?, ...) 
[DEBUG] 2017-10-18 18:43:45,770 com...xxxDao.saveRequest - ==> Parameters: 281(Long), ..., 2017-10-18 16:43:45.493(Timestamp)
[DEBUG] 2017-10-18 18:43:45,783 com...xxxDao.saveRequest - <==    Updates: 1

在数据库中,这是结果:

select request_date from table_a
result: 2017-10-18 16:43:45.493

没关系,因为我在数据库中使用GMT时区。

然后我正在使用不同的mapper类在相同的数据源上执行另一个sql插件(POJO不同,但是Java和SQL类型是相同的)。问题是日期时间值是使用GMT+2时区插入数据库而不是GMT

[INFO ] 2017-10-18 18:43:46,188 com..................... - yyy-yyy-yyy: 2017-10-18T18:43:46.188+02:00[Europe/Prague]
[DEBUG] 2017-10-18 18:43:46,190 com...yyyDao.saveMetadata - ==>  Preparing: INSERT INTO table_b (id,..., uploaded) VALUES (?, ?, ...) 
[DEBUG] 2017-10-18 18:43:46,202 com...yyyDao.saveMetadata - ==> Parameters: 561(Long), ..., 2017-10-18 18:43:46.188(Timestamp)
[DEBUG] 2017-10-18 18:43:46,212 com...yyyDao.saveMetadata - <==    Updates: 1

正如您所看到的,该值插入了错误的时区:

select uploaded from table_b
result: 2017-10-18 18:43:46.188

我的第一个猜测是它来自错误的数据库池设置,因此我将以下属性添加到我的池配置中:

sessionTimeZone=UTC

但我仍然在UTC中插入第一个日期时间,在UTC + 2时区插入第二个日期时间。

我试图注销java.sql.Connection的细节,看看到底是怎么回事,所以我把SqlSqssion注入到我的代码中(@Inject SqlSession sqlSession)但当然我得到了org.apache.ibatis.session.SqlSessionException: Error: Cannot get connection. No managed session is started..异常,因为我使用MANAGED事务处理。

知道该检查什么?

-----更新1 -----

所以我根据建议将所有内容都改为UTC:

  • postgresql.conf:timezone =&#39; UTC&#39;
  • app server:-Duser.timezone = UTC

似乎没关系,但是......

当我在PostgreSQL控制台中执行查询时,结果如下:

demo=# select EXTRACT(TIMEZONE FROM uploaded), uploaded from image_metadata;
 date_part |          uploaded
-----------+----------------------------
         0 | 2017-10-25 00:24:11.873+00
(1 row)

SqurielSQL中的相同查询结果:

date_part   uploaded
0           2017-10-25 02:24:11.873

似乎我的SQL客户端在后台进行了一些棘手的时区对话,但我不确定。我需要检查一下。

-----更新2 -----

我不确定问题是什么,但在将数据库和JVM时区设置更改为UTC后,我的问题已解决。

我使用以下SQL查询从数据库中获取存储的日期时间值:

SELECT current_timestamp AT TIME ZONE 'UTC'

1 个答案:

答案 0 :(得分:0)

我会将所有内容设置为UTC以使一切变得更简单。

LOGGER.info(TimeZone.getDefault().getID())

如果显示除UTC之外的任何内容,则将VM参数-Duser.timezone=UTC添加到应用程序启动。

代码段变量request / httpRequest中存在混淆,可能只是一个拼写错误?

  

请求 .setRequestDate = ZonedDateTime.now();

     

LOGGER.info(&#34; xxx-xxx-xxx:&#34; + httpRequest .getRequestDate());