【问题标题】:Use BIGINT column for java.util.Date or java.time.Instant in JPA/Hibernate在 JPA/Hibernate 中为 java.util.Date 或 java.time.Instant 使用 BIGINT 列
【发布时间】:2012-11-18 18:44:21
【问题描述】:

我需要访问使用BIGINT 列来存储时间戳的现有 MySQL 数据库:

create table mytable (created bigint);

现在我更喜欢使用 java.util.Datejava.time.Instant 实例而不是整数,所以我试图让 Hibernate 直接转换值。不幸的是,当这样注释时,Hibernate 将无法识别该列:

@Column(name = "created")
private Date created;

或者像这样:

@Column(name = "created")
@Temporal(TemporalType.TIMESTAMP)
private Calendar created;

这确实会在未来返回一些东西,比如2017-07-01T04:14:00+02:00。如何让 Hibernate 正确转换 BIGINT 列,这样我就不必在 getter 和 setter 中转换它们?

【问题讨论】:

  • 这样存储时是否与时间戳一起使用? (第二个例子)这样你就不用再在使用之前对数据进行操作了,写的就是读的?
  • 我发现存储的时间戳是自纪元以来的秒数,而不是休眠时预期的毫秒数。我创建了一个 UnixTimestampType,它将值从秒转换为毫秒,反之亦然。
  • 那么恭喜你的探索性努力:D

标签: java hibernate jpa


【解决方案1】:

Hibernate 的 TemporalType.TIMESTAMP 映射到 java.sql.TimestampTimestamp 构造函数采用 Long 值,即自纪元以来的毫秒数。数据库中的值存储为 Unix 时间戳,即自纪元以来的秒数。

我写了一个 UnixTimestampType,它需要几秒钟而不是几毫秒,并创建 Date 实例:

public class UnixTimestampType extends AbstractSingleColumnStandardBasicType<Date> implements IdentifierType<Date>, LiteralType<Date> {
    private static final long serialVersionUID = 1L;
    public static final UnixTimestampType INSTANCE = new UnixTimestampType();

    public UnixTimestampType() {
        super(UnixTimestampTypeDescriptor.INSTANCE, JdbcDateTypeDescriptor.INSTANCE);
    }

    @Override
    public String getName() {
        return "date";
    }

    @Override
    public String[] getRegistrationKeys() {
        return new String[] { getName(), java.sql.Date.class.getName() };
    }

    @Override
    public String objectToSQLString(Date value, Dialect dialect) throws Exception {
        final java.sql.Date jdbcDate = java.sql.Date.class.isInstance(value) ? (java.sql.Date) value : new java.sql.Date(value.getTime());
        return StringType.INSTANCE.objectToSQLString(jdbcDate.toString(), dialect);
    }

    @Override
    public Date stringToObject(String xml) {
        return fromString(xml);
    }
}

public class UnixTimestampTypeDescriptor implements SqlTypeDescriptor {
    private static final long serialVersionUID = 1L;
    public static final UnixTimestampTypeDescriptor INSTANCE = new UnixTimestampTypeDescriptor();

    @Override
    public int getSqlType() {
        return Types.INTEGER;
    }

    @Override
    public boolean canBeRemapped() {
        return true;
    }

    @Override
    public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
        return new BasicBinder<X>(javaTypeDescriptor, this) {
            @Override
            protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {
                Date date = javaTypeDescriptor.unwrap(value, Date.class, options);
                date.setTime(date.getTime() / 1000);
                st.setDate(index, date);
            }
        };
    }

    @Override
    public <X> ValueExtractor<X> getExtractor(final JavaTypeDescriptor<X> javaTypeDescriptor) {
        return new BasicExtractor<X>(javaTypeDescriptor, this) {
            @Override
            protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
                Date date = new Date(rs.getLong(name) * 1000);
                return javaTypeDescriptor.wrap(date, options);
            }
        };
    }
}

【讨论】:

    猜你喜欢
    • 2019-07-05
    • 2021-05-30
    • 1970-01-01
    • 2018-08-24
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    相关资源
    最近更新 更多