首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Hibernate 擴充 @CreationTimestamp/@UpdateTimestamp 支援 Java 8 時間類型

     編輯:Java 相關知識

從 java.util.Date 到 java.time.LocalDateTime:註解值生成器的遞移適配

Hibernate 4.3.x 內建時間戳註解僅支援 Date、Calendar、Timestamp 等舊類型。Java 8 java.time 套件(LocalDateTime、LocalDate、LocalTime)成為新標準,需自訂 AnnotationValueGeneration 實作註冊至 Hibernate,實現實體欄位自動填充創建/更新時間。

核心抽象類實作

public abstract class AbstractTimeGeneration<A extends Annotation> 
        implements AnnotationValueGeneration<A> {

    protected ValueGenerator<?> generator;

    @Override
    public void initialize(A annotation, Class<?> propertyType) {
        if (LocalDateTime.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> LocalDateTime.now();
        } else if (LocalDate.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> LocalDate.now();
        } else if (LocalTime.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> LocalTime.now();
        } else if (java.sql.Date.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> new java.sql.Date(System.currentTimeMillis());
        } else if (Time.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> new Time(System.currentTimeMillis());
        } else if (Timestamp.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> new Timestamp(System.currentTimeMillis());
        } else if (Date.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> new Date();
        } else if (Calendar.class.isAssignableFrom(propertyType)) {
            generator = (session, owner) -> {
                Calendar cal = Calendar.getInstance();
                cal.setTime(new Date());
                return cal;
            };
        } else {
            throw new HibernateException("Unsupported type for " + annotation.getClass().getSimpleName());
        }
    }

    @Override public ValueGenerator<?> getValueGenerator() { return generator; }
    @Override public boolean referenceColumnInSql() { return false; }
    @Override public String getDatabaseGeneratedReferencedColumnValue() { return null; }
}

具體註解綁定

// 1. 定義註解(保留策略 RUNTIME,目標 FIELD/METHOD)
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CreationTimestamp {}

// 2. 實作生成器(繼承抽象類)
public class CreationTimestampGenerator 
    extends AbstractTimeGeneration<CreationTimestamp> {}

// 3. 註冊至 Hibernate(hibernate.cfg.xml 或 persistence.xml)
// 
//     com.yourpkg.CreationTimestampGenerator
// 
// 或程式碼註冊:
// MetadataSources src = new MetadataSources(...);
// src.getMetadataBuilder().applyValueGenerators(...);

實體使用範例

@Entity
public class Article {
    @Id @GeneratedValue Long id;
    String title;
    
    @CreationTimestamp
    @Column(updatable = false) // 僅創建時設定
    LocalDateTime createdAt;

    @UpdateTimestamp // 需同理實作 UpdateTimestampGenerator
    LocalDateTime updatedAt;
}

注意事項與替代方案

  • 時區一致性:LocalDateTime.now() 使用 JVM 預設時區,分布式系統建議統一 UTC,或改用 OffsetDateTime、Instant。
  • Hibernate 5.2+:已內建支援 java.time 類型(需 hibernate-java8 模組),可直接用 @CreationTimestamp 無需自訂生成器。
  • JPA 標準:@PrePersist/@PreUpdate 回調方法同樣可實現,無需擴充 Hibernate SPI,移植性更好。
  • 資料庫層面:DEFAULT CURRENT_TIMESTAMP、ON UPDATE CURRENT_TIMESTAMP(MySQL)或 Trigger(PostgreSQL/Oracle)更可靠,不依賴應用層時鐘。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved