繁体   English   中英

如何将 TIMESTAMP 列映射到 ZonedDateTime JPA 实体属性?

[英]How to map a TIMESTAMP column to a ZonedDateTime JPA entity property?

我正在使用 Spring 数据jpamariadb最新版本,以及MariaDB 10.3.16

+--- org.springframework.boot:spring-boot-starter-data-jpa -> 2.1.5.RELEASE
...
|    +--- org.springframework.boot:spring-boot-starter-jdbc:2.1.5.RELEASE
...
|    +--- org.hibernate:hibernate-core:5.3.10.Final

这是我的实体:

@Entity
@Data
@Table
@NoArgsConstructor
@AllArgsConstructor
public class Note {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;

    @Column
    private String gsn;

    @Column
    @Enumerated(EnumType.STRING)
    private NoteType type;

    @Column
    private String text;

    @Column
    private ZonedDateTime scheduleDt;

    @Column
    @CreationTimestamp
    private Instant createDt;

    @Column
    @UpdateTimestamp
    private ZonedDateTime updateDt;
}

当我坚持我的实体时,Hibernate 尝试将ZonedDateTime成员保存为DATETIME列。 但我想使用TIMESTAMP列而不是DATETIME列。

这是创建 DDL,我从日志中看到的。

create table `note` (`id` integer not null, `create_dt` datetime,
    `gsn` varchar(255), `schedule_dt` datetime, `text` varchar(255),
    `type` varchar(255), `update_dt` datetime, primary key (`id`)) 
  engine=MyISAM

这里create_dtschedule_dtupdate_dt被创建为datetime列类型,这是我不想要的。 (我也不喜欢 MyISAM)。

我该如何解决?


添加是因为注释无法表达 ddl。

当我使用 columnDefinition 属性时,生成的 ddl 是 ...

create table `note` (`id` integer not null, `create_dt` datetime,
    `gsn` varchar(255), `schedule_dt` datetime, `text` varchar(255),
    `type` varchar(255), `update_dt` `TIMESTAMP`, primary key (`id`)) 

引擎=MyISAM

TIMESTAMP 周围有不需要的“`”。

JPA 2.2 支持映射 Java 8 日期/时间 API,但仅适用于以下类型:

但是,Hibernate 也支持ZonedDateTime ,就像这样。

保存ZonedDateTime ,以下Timestamp将发送到PreparedStatement

Timestamp.from( zonedDateTime.toInstant() )

而且,从数据库中读取时,则ResultSet将包含一个Timestamp将被转化为一个ZonedDateTime ,就像这样:

ts.toInstant().atZone( ZoneId.systemDefault() )

请注意, ZoneId未存储在数据库中,因此基本上,如果此Timestamp转换不适合您,则最好使用LocalDateTime

因此,让我们假设我们有以下实体:

@Entity(name = "UserAccount")
@Table(name = "user_account")
public class UserAccount {

    @Id
    private Long id;

    @Column(name = "first_name", length = 50)
    private String firstName;

    @Column(name = "last_name", length = 50)
    private String lastName;

    @Column(name = "subscribed_on")
    private ZonedDateTime subscribedOn;

    //Getters and setters omitted for brevity
}

请注意, subscribedOn属性是一个ZonedDateTime Java 对象。

持久化UserAccount

UserAccount user = new UserAccount()
    .setId(1L)
    .setFirstName("Vlad")
    .setLastName("Mihalcea")
    .setSubscribedOn(
        LocalDateTime.of(
            2020, 5, 1,
            12, 30, 0
        ).atZone(ZoneId.systemDefault())
    );

entityManager.persist(user);

Hibernate 生成正确的 SQL INSERT 语句:

INSERT INTO user_account (
    first_name, 
    last_name, 
    subscribed_on, 
    id
) 
VALUES (
    'Vlad', 
    'Mihalcea', 
    '2020-05-01 12:30:00.0', 
    1
)

在获取UserAccount实体时,我们可以看到从数据库中正确获取了ZonedDateTime

UserAccount userAccount = entityManager.find(
    UserAccount.class, 1L
);

assertEquals(
    LocalDateTime.of(
        2020, 5, 1,
        12, 30, 0
    ).atZone(ZoneId.systemDefault()),
    userAccount.getSubscribedOn()
);

您可以使用 @Column 注释定义列类型:

@Column(columnDefinition="TIMESTAMP")  
@UpdateTimestamp
private ZonedDateTime updateDt;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM