当前位置: 首页 > 知识库问答 >
问题:

如何将Java 8 LocalDateTime与JPA和Hibernate一起使用

宰父保臣
2023-03-14

我有以下的类描述片段:

... 
@Column(name = "invalidate_token_date")
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime invalidateTokenDate;
....

此代码在HiberNate 4上不起作用,因为@Temporal不支持LocalDateTime。

我从Joda Time看到了关于如何使用LocalDateTime的建议,但我使用的是Java 8。

共有3个答案

邰博远
2023-03-14

如果可以使用Java EE 7,则有更优雅的解决方案:

@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Date> {

    @Override
    public Date convertToDatabaseColumn(LocalDateTime date) {
        if (date == null){
            return null;
        }
        return date.toDate();
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Date value) {
        if (value == null) {
            return null;
        }
        return LocalDateTime.fromDateFields(value);
    }
} 
... 
@Column(name = "invalidate_token_date")
private LocalDateTime invalidateTokenDate;
....

(autoApply=true)表示@Converter自动用于JPA实体中每个LocalDateTime属性的转换。

顺便说一句,AttributeConverter也非常适合映射枚举。

诸葛茂勋
2023-03-14

由于HiberNate 4不支持它,您需要实现一个用户类型,如本示例所示。

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.usertype.EnhancedUserType;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

public class LocalDateTimeUserType implements EnhancedUserType, Serializable {

    private static final int[] SQL_TYPES = new int[]{Types.TIMESTAMP};

    @Override
    public int[] sqlTypes() {
        return SQL_TYPES;
    }

    @Override
    public Class returnedClass() {
        return LocalDateTime.class;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        if (x == y) {
            return true;
        }
        if (x == null || y == null) {
            return false;
        }
        LocalDateTime dtx = (LocalDateTime) x;
        LocalDateTime dty = (LocalDateTime) y;
        return dtx.equals(dty);
    }

    @Override
    public int hashCode(Object object) throws HibernateException {
        return object.hashCode();
    }


    @Override
    public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
            throws HibernateException, SQLException {
        Object timestamp = StandardBasicTypes.TIMESTAMP.nullSafeGet(resultSet, names, session, owner);
        if (timestamp == null) {
            return null;
        }
        Date ts = (Date) timestamp;
        Instant instant = Instant.ofEpochMilli(ts.getTime());
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    @Override
    public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
            throws HibernateException, SQLException {
        if (value == null) {
            StandardBasicTypes.TIMESTAMP.nullSafeSet(preparedStatement, null, index, session);
        } else {
            LocalDateTime ldt = ((LocalDateTime) value);
            Instant instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
            Date timestamp = Date.from(instant);
            StandardBasicTypes.TIMESTAMP.nullSafeSet(preparedStatement, timestamp, index, session);
        }
    }

    @Override
    public Object deepCopy(Object value) throws HibernateException {
        return value;
    }

    @Override
    public boolean isMutable() {
        return false;
    }

    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (Serializable) value;
    }

    @Override
    public Object assemble(Serializable cached, Object value) throws HibernateException {
        return cached;
    }

    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }

    @Override
    public String objectToSQLString(Object object) {
        throw new UnsupportedOperationException();
    }

    @Override
    public String toXMLString(Object object) {
        return object.toString();
    }

    @Override
    public Object fromXMLString(String string) {
        return LocalDateTime.parse(string);
    }

}

然后,可以在带有@Type注释的映射中使用新的usertype。例如。

@Type(type="com.hibernate.samples.type.LocalDateTimeUserType")
@Column(name = "invalidate_token_date")
private LocalDateTime invalidateTokenDate;

@Type注释需要实现userType接口的类的完整路径;这是用于生成映射列的目标类型的工厂。

下面是如何在JPA2.1中做同样的事情

左丘涵畅
2023-03-14

对于任何HiberNate 5. x用户,都有

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-java8</artifactId>
    <version>5.0.0.Final</version>
</dependency>

你不需要做任何其他事情。只需添加依赖项,Java8时间类型就可以像其他基本类型一样工作,不需要注释。

private LocalDateTime invalidateTokenDate;

注意:这不会保存到时间戳类型。使用MySQL进行测试时,它会保存到datetimetype。

 类似资料:
  • =============编辑: 下面是我的新配置: 实体: 编辑3: --已删除(字符限制)-- 编辑4:

  • 问题内容: 我有一个包含字符串类型主键的实体。该实体模型如下: 但是我面临说TypeMismatch的问题。 问题答案: 如果您未指定ID生成策略,则Hibernate将使用。这将导致 AUTO-标识列,序列或表,具体取决于基础数据库。 如果你看看这里,你会发现所有的生成类型的IDS,或,不是类型。 假设您要使用UUID作为ID,则可以使用

  • 在谷歌搜索了很多之后,现在感到困惑和沮丧。 我正在将一个应用程序从Hibernate 3升级到4。这在使用dtd 3.0时效果很好,但现在需要使用4.0 xsd,而这正是一切都要基于apex的地方! 该应用程序使用hbm.xml文件来配置每个实体,没有任何注释。 找到hbm文件的示例将非常有用,但即使是hibernate 4的教程也只使用3.0 dtd! 我正在使用以下内容 使用它,我得到了一个长

  • 问题内容: 我想用MySQL和JPA设置Spring Boot。为此,我创建: Person PersonRepository PersonController 开始课程示例: 对于数据库配置,我创建了application.properties 所以我有项目结构: 但是结果是我有例外: 问题答案: 我像你一样创建了一个项目。结构看起来像这样 这些类只是复制自你的类。 我将application.

  • 问题内容: 我是Spring的新手。 我们正在使用Spring Security功能。数据库连接:JPA的eclipselink实现。数据库:MySql 使用spring security时,身份验证提供程序的配置如下- 但是在JPA中,我们没有定义数据源,我们将Persistence unit与provider一起使用 那么,我们如何配置身份验证提供程序,以便将JPA用于数据库连接? 数据源引用

  • 问题内容: 我在理解Hibernate如何处理泛型时遇到一些麻烦,并且想知道实现我的目标的最佳方法。 给定一个简单的通用实体: 在进行hibernate初始化时,出现异常: 我几乎可以肯定,这是因为我没有给hibernate一些可能的限制条件。我知道你可以指定的东西,如上面的注释,但你失去使用泛型的灵活性。我可以使用注解限制可接受的泛型的范围吗?例如:如果我想要class ,该类从抽象类继承而来,