首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >使用hibernate存储错误的LocalDate

使用hibernate存储错误的LocalDate
EN

Stack Overflow用户
提问于 2019-06-23 00:02:51
回答 3查看 2.1K关注 0票数 3

我试图将餐馆预订的日期存储在数据库中,但是,即使提交的日期是正确的,hibernate在数据库中存储的日期比我提交的日期早一天。我不知道为什么。可能是时区问题,但我不明白为什么.日期不应受时区的影响。

以下是我的spring引导属性文件:

代码语言:javascript
代码运行次数:0
运行
复制
spring:
  thymeleaf:
    mode: HTML5
    encoding: UTF-8
    cache: false
  jpa:
    database: MYSQL
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        locationId:
          new_generator_mappings: false
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        jdbc:
          time_zone: UTC
  datasource:
    driver:
      class: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/databaseName?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
    username: username
    password: **********

我来自意大利,所以我的时区是:

  • 标准时间GMT/UTC + 1h
  • 夏令时GMT/UTC + 2h

目前我们是UTC + 2h。

我要存储的对象是这个:

代码语言:javascript
代码运行次数:0
运行
复制
@Entity
public class Dinner {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long dinnerId;

    private LocalDate date;
    ...

我用来拦截POST请求的控制器是:

代码语言:javascript
代码运行次数:0
运行
复制
@PreAuthorize("hasRole('USER')")
@PostMapping
public String createDinner(@RequestParam(value="dinnerDate") String dinnerDate, Principal principal, Model model){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate date = LocalDate.parse(dinnerDate, formatter);
        dinnerService.createDinner(date);
        return "redirect:/dinners?dinnerDate=" + dinnerDate;
}

它调用服务方法createDinner,该方法调用Jpa方法保存以存储对象。我正在使用thymeleaf来处理html模板。如果我在数据库中提交日期为30/6/2019,我将得到29/6/2019。当我按日期检索晚餐对象时,如果插入30/6/2019,就会得到日期为29/6/2019的晚餐。所以看起来春天用一种奇怪的方式来处理日期..。考虑某种时区,但我不知道如何禁用或处理它。有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-06-29 10:00:33

  1. 您不需要为模式yyyy-MM-dd定义格式。LocalDate#parse默认使用DateTimeFormatter.ISO_LOCAL_DATE,这意味着LocalDate.parse("2020-06-29")在不显式应用格式的情况下工作。
  2. 既然你已经知道你时区的日期和世界协调时的时间不同,你就不应该只考虑一个日期;你应该同时考虑日期和时间,例如,2020年-06-29号世界协调时11:30下午11:30将落在你时区的2020-06-30。因此,您应该做的第一件事是将字段的类型更改为数据库中的TIMESTAMP
  3. 将字段类型更改为TIMESTAMP后,将方法createDinner更改如下: LocalDateTime dinnerDateTime = LocalDateTime.of(LocalDate.parse(dinnerDate),LocalTime.of(0,0,0,0)),OffsetDateTime odt =dinnerDateTime.atOffset(ZoneOffset.UTC),dinnerService.createDinner(odt); 然后在DinnerService内部(或者在编写了在数据库中插入/更新记录的逻辑的地方的DinnerServiceDAO ): pst.setObject(index ); 其中,pst表示PreparedStatement的对象,index表示插入/更新查询中该字段的索引(从1开始)。
票数 0
EN

Stack Overflow用户

发布于 2019-12-05 12:17:37

假设您的时区是:欧洲/意大利,您必须设置您的serverTimezone变量如下:

网址: jdbc:mysql://localhost:3306/databaseName?useSSL=false&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Europe/Italy

票数 0
EN

Stack Overflow用户

发布于 2020-06-26 14:15:15

同样的问题(同一个国家!:-)。

我怀疑,如果hibernate或jpa是用时区UTC设置的,而当日期持久化时机器是用默认的时区== Europe/Rome设置的,那么它将自动从机器时区转换为数据库时区,如果在DB上存储了所有的UTC格式的日期,这不是一个坏特性。

当您在持久化之前转换日期时会发生此问题:它会被转换两次。至少这是我的案子。

仍然在寻找最好的解决方案!如果我能找到一个,我稍后会把它加到答案中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56720029

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档