使用 Hibernate ORM 从 postgres 获取 TIMESTAMP 作为 LocalDatetime

Getting a TIMESTAMP from postgre as a LocalDatetime with HibernateORM

我有这个 Hibernate 模型

package net.nebulacraft.nebulous.Data.Models;

import org.bukkit.command.CommandSender;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.UUID;

@Entity
@Table(name = "warning")
public class Warning {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "warningid")
    int WarningId;
    @Column(name = "userid")
    UUID Player;
    @Column(name = "rulenumber")
    int RuleNumber;
    @Column(name = "expiration")
    LocalDateTime Expiration;
    @Column(name = "datecreated")
    LocalDateTime DateCreated;
    @Column(name = "warnedby")
    UUID WarnedBy;
    @Column(name = "message")
    String Message;
    public UUID getPlayer() {
        return Player;
    }
    public void setPlayer(UUID player) {
        Player = player;
    }
    public int getRuleNumber() {
        return RuleNumber;
    }
    public void setRuleNumber(int ruleNumber) {
        RuleNumber = ruleNumber;
    }
    public LocalDateTime getExpiration() {
        return Expiration;
    }
    public void setExpiration(LocalDateTime expiration) {
        Expiration = expiration;
    }
    public LocalDateTime getDateCreated() {
        return DateCreated;
    }
    public void setDateCreated(LocalDateTime dateCreated) {
        DateCreated = dateCreated;
    }
    public UUID getWarnedBy() {
        return WarnedBy;
    }
    public void setWarnedBy(UUID warnedBy) {
        WarnedBy = warnedBy;
    }
    public String getMessage() {
        return Message;
    }
    public void setMessage(String message) {
        Message = message;
    }
    public int getWarningId() {
        return WarningId;
    }
    public void setWarningId(int warningId) {
        WarningId = warningId;
    }
}

我可以使用 session.save(warning); session.getTransaction().commit(); 将新警告插入数据库,警告是警告的实例,会话是休眠会话。但是,尝试从数据库中获取 Warning 的实例

    public static List<Warning> GetWarnings(UUID player) {
        var session = DbFactory.getSessionFactory().openSession();
        var builder = session.getCriteriaBuilder();
        var query = builder.createQuery(Warning.class);
        var root = query.from(Warning.class);

        query.select(root);
        query.where(
                builder.and(
                        builder.equal(root.get("Player"), player),
                        builder.greaterThan(root.get("Expiration"), new Date())
                )
        );
        query.orderBy(builder.desc(root.get("DateCreated")));
        return session.createQuery(query).getResultList();
    }

导致以下错误: java.lang.ClassCastException: class java.util.Date cannot be cast to class java.time.LocalDateTime (java.util.Date and java.time.LocalDateTime are in module java.base of loader 'bootstrap')

Hibernate 向数据库中插入一个 LocalDatetime 似乎没有问题,为什么我不能从数据库中取回一个?

在 postgre 中,Expiration 和 DateCreated 列的数据类型都是“timestamp without time zone”

你说:

Both the Expiration and DateCreated columns have data type "timestamp without time zone" in postgre

数据库类型错误

您为数据库列使用了错误的数据类型。

TIMESTAMP WITHOUT TIME ZONE Postgres 类型故意缺少任何时区或 offset-from-UTC 的概念。所以这个类型不能用来表示一个时刻,不能是时间轴上的一个具体点。

跟踪时间轴上特定点的时刻时,始终使用 TIMESTAMP WITH TIME ZONE.

类型的列

输入错误 Java

同样,你用错了Java class.

LocalDateTime class 故意缺少任何时区或 offset-from-UTC 的概念。所以这个类型不能用来表示一个时刻,不能是时间轴上的一个具体点。

而是使用 OffsetDateTime class 从 TIMESTAMP WITH TIME ZONE.

的列中检索值
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

避免遗留 date-time classes

这两个 Date classes 现在都是遗留的,多年前被现代 java.time classes 所取代JSR 310.

无需使用旧版 classes。它们的功能完全被 java.time classes.

取代
  • java.util.Date 替换为 java.time.Instant
  • java.sql.Date 替换为 java.time.LocalDate

对于数据库工作,使用:

  • java.time.OffsetDateTime 用于类似于 SQL-standard 类型的数据库列 TIMESTAMP WITH TIME ZONE.
  • java.time.LocalDateTime 用于类似于 SQL-standard 类型的数据库列 TIMESTAMP WITHOUT TIME ZONE.

JDBC 4.2+, Jakarta Persistence (JPA), and Hibernate全部更新支持java.time.