MyBatis + MyBatis CDI + PostgreSQL 的时区问题
time zone issue with MyBatis + MyBatis CDI + PostgreSQL
我在 MyBatis 中有一个奇怪的时区问题。
环境:
- mybatis v3.4.5
- mybatis-cdi v1.0.1
- Payara 应用服务器 v4.1.2.173
- PostgreSQL 数据库
- JNDI 数据源,MANAGED 事务设置
首先 我在 table 中插入一条记录,其中有一个日期时间字段。
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 时区。
然后 我正在使用不同的映射器 class 在同一个数据源上执行另一个 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: 时区 = 'UTC'
- 应用服务器:-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)
Squriel 查询结果相同SQL:
date_part uploaded
0 2017-10-25 02:24:11.873
我的 SQL 客户端似乎在后台进行了一些棘手的时区对话,但我不确定。我需要检查一下。
----- 更新 2 -----
我不确定是什么问题,但在我将数据库和 JVM 时区设置更改为 UTC 后我的问题得到了解决。
我使用以下 SQL 查询从数据库中取回存储的日期时间值:
SELECT current_timestamp AT TIME ZONE 'UTC'
我会将所有内容都设置为 UTC 以简化一切。
LOGGER.info(TimeZone.getDefault().getID())
如果它显示的不是 UTC,则将 VM 参数 -Duser.timezone=UTC
添加到应用程序启动。
片段变量 request
/ httpRequest
中存在混淆,可能只是错字?
request.setRequestDate = ZonedDateTime.now();
LOGGER.info("xxx-xxx-xxx: " + httpRequest.getRequestDate());
我在 MyBatis 中有一个奇怪的时区问题。
环境:
- mybatis v3.4.5
- mybatis-cdi v1.0.1
- Payara 应用服务器 v4.1.2.173
- PostgreSQL 数据库
- JNDI 数据源,MANAGED 事务设置
首先 我在 table 中插入一条记录,其中有一个日期时间字段。
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 时区。
然后 我正在使用不同的映射器 class 在同一个数据源上执行另一个 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: 时区 = 'UTC'
- 应用服务器:-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)
Squriel 查询结果相同SQL:
date_part uploaded
0 2017-10-25 02:24:11.873
我的 SQL 客户端似乎在后台进行了一些棘手的时区对话,但我不确定。我需要检查一下。
----- 更新 2 -----
我不确定是什么问题,但在我将数据库和 JVM 时区设置更改为 UTC 后我的问题得到了解决。
我使用以下 SQL 查询从数据库中取回存储的日期时间值:
SELECT current_timestamp AT TIME ZONE 'UTC'
我会将所有内容都设置为 UTC 以简化一切。
LOGGER.info(TimeZone.getDefault().getID())
如果它显示的不是 UTC,则将 VM 参数 -Duser.timezone=UTC
添加到应用程序启动。
片段变量 request
/ httpRequest
中存在混淆,可能只是错字?
request.setRequestDate = ZonedDateTime.now();
LOGGER.info("xxx-xxx-xxx: " + httpRequest.getRequestDate());