You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring JPA中@EmbeddedId内使用时间戳注解的可行性问询

问题解答

结论:不能直接在@EmbeddedId中使用@CreationTimestamp和@UpdateTimestamp

JPA的主键字段(包括嵌入主键)执行save()操作时,要求必须有明确赋值。而@CreationTimestamp/@UpdateTimestamp依赖数据库自动生成值,此时JPA会判定嵌入主键中的时间戳字段为空,触发数据库非空约束错误。这也是时间戳移到主实体类就能正常工作的原因——非主键字段允许由数据库自动生成值,不会触发主键约束检查。

满足需求的解决方案(时间戳保留在@EmbeddedId中)

要实现数据库自动生成时间戳,同时让JPA在保存后获取到这些值,可通过数据库层配置默认值+触发器,配合JPA字段属性设置实现:

1. 数据库表结构配置(PostgreSQL)

在数据库中为时间戳字段设置默认值,并创建触发器自动更新update_timestamp:

-- 创建表
CREATE TABLE complex_entity (
    pkey BIGINT NOT NULL,
    create_timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    update_timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    field_example VARCHAR(255),
    PRIMARY KEY (pkey, create_timestamp, update_timestamp)
);

-- 创建更新update_timestamp的触发器函数
CREATE OR REPLACE FUNCTION update_modified_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.update_timestamp = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 绑定触发器到表
CREATE TRIGGER update_complex_entity_modtime
BEFORE UPDATE ON complex_entity
FOR EACH ROW EXECUTE FUNCTION update_modified_column();

2. 修改JPA实体代码

调整嵌入主键类的字段配置,告诉JPA不要自动插入/更新时间戳字段,同时添加方法在保存后刷新实体以获取数据库生成的时间戳:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class ComplexPkey {
   @Column(name = "pkey", nullable = false) 
   private Long pkey;
   
   // 禁止JPA插入/更新该字段,由数据库负责生成
   @Column(name = "create_timestamp", nullable = false, insertable = false, updatable = false)
   private Date createTimestamp;
   
   // 禁止JPA插入/更新该字段,由触发器负责更新
   @Column(name = "update_timestamp", nullable = false, insertable = false, updatable = false)
   private Date updateTimestamp;
}

@Getter
@Setter
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ComplexEntity {
    @EmbeddedId
    private ComplexPkey pkey;
    
    private String fieldExample;
    
    // 保存/更新后刷新实体,获取数据库生成的时间戳
    @PostPersist
    @PostUpdate
    private void refreshTimestamps() {
        EntityManager em = PersistenceContextHolder.getEntityManager();
        if (em != null) {
            em.refresh(this);
        }
    }
}

说明

  • insertable = false, updatable = false:告知JPA在生成INSERT/UPDATE语句时忽略这两个时间戳字段,完全由数据库控制它们的值。
  • @PostPersist/@PostUpdate:在实体保存或更新完成后,调用EntityManager.refresh()从数据库拉取最新的实体数据,确保嵌入主键中的时间戳字段被填充。

内容的提问来源于stack exchange,提问作者Bohdan Lishchuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 14:15:57