oiz*_*ain 7 java postgresql timezone jpa spring-boot
环境
问题
我正在构建一个Spring Boot微服务,它与不同的服务共享一个Postgresql数据库.数据库在外部初始化(在我们的控制之外),其他服务使用的日期时间列类型是没有时区的时间戳.因此,由于我希望db上的所有日期具有相同的类型,因此具有该类型是我的JPA实体日期的要求.
我在JPA实体对象上映射它们的方式如下:
@Column(name = "some_date", nullable = false)
private Timestamp someDate;
Run Code Online (Sandbox Code Playgroud)
问题是,当我按如下方式创建时间戳时:
new java.sql.Timestamp(System.currentTimeMillis())
Run Code Online (Sandbox Code Playgroud)
我查看数据库,时间戳包含我当地的时区日期时间,但我想将其存储在UTC中.这是因为我的默认时区设置为'Europe/Brussels',JPA/JDBC将我的java.sql.Timestamp对象转换为我的时区,然后再将其放入数据库.
找不到理想的解决方案
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));具有我想要实现的效果,但它不适合,因为它不是特定于我的服务.即它会影响整个JVM或当前线程加上孩子.
启动应用程序-Duser.timezone=GMT似乎也为正在运行的JVM的单个实例执行任务.因此,比前一个更好的解决方案.
但有没有办法在JPA/datasource/spring启动配置中指定时区?
我能解决问题的最合适的解决方法是使用a AttributeConverter将Java 8 ZonedDateTime对象转换为java.sql.Timestamp对象,以便它们可以映射到PostgreSQL timestamp without time zone类型.
您需要的原因AttributeConverter是因为Java 8/Joda时间日期时间类型尚未与JPA兼容.
该AttributeConverter如下所示:
@Converter(autoApply = true)
public class ZonedDateTimeAttributeConverter implements AttributeConverter<ZonedDateTime, Timestamp> {
@Override
public Timestamp convertToDatabaseColumn(ZonedDateTime zonedDateTime) {
return (zonedDateTime == null ? null : Timestamp.valueOf(zonedDateTime.toLocalDateTime()));
}
@Override
public ZonedDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime().atZone(ZoneId.of("UTC")));
}
}
Run Code Online (Sandbox Code Playgroud)
这允许我读取没有时区信息的数据库时间戳作为ZonedDateTime具有UTC时区的对象.这样我就可以在数据库中看到确切的日期时间,无论我的应用运行的时区如何.
由于toLocalDateTime()还应用了系统的默认时区转换,这AttributeConverter基本上取消了JDBC驱动程序应用的转换.
timestamp without timezone吗?实际情况是,如果您在时区上存储日期时间信息(即使它是UTC),timestamp without timezonePostgreSQL类型是错误的选择.要使用的正确数据类型timestamp with timezone包括时区信息.更多关于此主题的信息.
但是,如果出于某种原因,你必须使用timestamp without timezone,我认为ZonedDateTime上面的方法是一个强大而一致的解决方案.
ZonedDateTimeJSON吗?然后你在你需要至少版本的事实可能感兴趣2.6.0的的jackson-datatype-jsr310依赖性的序列化工作.更多关于这个答案.
| 归档时间: |
|
| 查看次数: |
12385 次 |
| 最近记录: |