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

Spring Data JPA未触发DDL默认值填充问题求助

问题描述

我在Oracle中定义了如下表,CREATED_ON和CREATED_BY字段配置了DDL默认值:

CREATE TABLE CONFIGSERVER.PROPERTIES (
    ID NUMBER GENERATED ALWAYS AS IDENTITY ( START WITH 1 CACHE 20 ) ,
    APPLICATION VARCHAR2 (4000) ,
    PROFILE     VARCHAR2 (4000) ,
    LABEL       VARCHAR2 (4000) ,
    PROP_KEY    VARCHAR2 (4000) NOT NULL,
    VALUE       VARCHAR2 (4000) NOT NULL,
    CREATED_ON  TIMESTAMP DEFAULT SYSDATE,
    CREATED_BY  VARCHAR2 (100) DEFAULT COALESCE(
        REGEXP_SUBSTR(SYS_CONTEXT('USERENV','CLIENT_IDENTIFIER'),'^[^:]*'),
        SYS_CONTEXT('USERENV','SESSION_USER')),
    UPDATED_ON  TIMESTAMP ,
    UPDATED_BY  VARCHAR2 (100)
) LOGGING;

用SQLCl执行插入语句时,这两个字段能通过DDL默认值正确填充:

insert into properties (application, profile, label, prop_key, value) values ('nisse', 'bosse', 'bengt', 'olle', 'korv med mos');

查询结果:

SQL> select * from properties where application = 'nisse';

   ID APPLICATION    PROFILE    LABEL    PROP_KEY    VALUE           CREATED_ON                         CREATED_BY      UPDATED_ON    UPDATED_BY    
_____ ______________ __________ ________ ___________ _______________ __________________________________ _______________ _____________ _____________ 
   25 nisse          bosse      bengt    olle        korv med mos    18-NOV-22 07.19.07.000000000 PM    CONFIGSERVER

但使用Spring Data JPA插入数据时,这两个字段的默认值并未填充。我的Properties实体类如下:

package com.example.configcrud.model;

import javax.persistence.*;
import java.sql.Timestamp;

@Entity
@Table(name = "properties")
public class Properties {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "application")
    private String application;

    @Column(name = "profile")
    private String profile;

    @Column(name = "label")
    private String label;

    @Column(name = "prop_key")
    private String propKey;

    @Column(name = "value")
    private String value;

    @Column(name = "created_on", updatable = false)
    private Timestamp createdOn;

    @Column(name = "created_by", updatable = false)
    private String createdBy;

    public Properties(String application, String profile, String label, String propKey, String value) {
         this.application = application;
         this.profile = profile;
         this.label = label;
         this.propKey = propKey;
         this.value = value;
    }

    public Properties() {
    }

    public String getApplication() {
        return application;
    }

    public void setApplication(String application) {
        this.application = application;
    }

    public String getProfile() {
        return profile;
    }

    public void setProfile(String profile) {
        this.profile = profile;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public String getPropKey() {
        return propKey;
    }

    public void setPropKey(String propKey) {
        this.propKey = propKey;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public Timestamp getCreatedOn() {
        return createdOn;
    }

    public Timestamp setCreatedOn() {
        return createdOn;
    }

    public String getCreatedBy() {
        return createdBy;
    }

    public String setCreatedBy() {
        return createdBy;
    }

    @Override
    public String toString() {
        return "Properties [id=" + id + ", " +
                "application=" + application + ", " +
                "profile=" + profile + ", " +
                "label=" + label +
                "propkey=" + propKey +
                "value=" + value +
                "CreatedOn=" + createdOn +
                "CreatedBy=" + createdBy + "]";
    }
}

使用的Spring Data JPA依赖:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

请问如何让JPA使用DDL定义的默认值,避免其被覆盖?

解决方案

JPA默认会把实体类中未赋值的字段以NULL值插入数据库,覆盖DDL定义的默认值。要让数据库使用默认值,需要让JPA在生成INSERT语句时忽略这些字段,或者明确告知JPA使用数据库默认值。可以通过以下几种方式解决:

1. 修改@Column注解,添加insertable=false

在created_on和created_by字段的@Column注解中添加insertable = false,这样JPA生成INSERT语句时不会包含这两个字段,数据库就会自动使用DDL定义的默认值:

@Column(name = "created_on", updatable = false, insertable = false)
private Timestamp createdOn;

@Column(name = "created_by", updatable = false, insertable = false)
private String createdBy;

注意:设置后这两个字段只能由数据库填充,无法通过JPA主动插入值。插入后调用saveAndFlush等方法,JPA会自动从数据库加载生成的字段值到实体对象中。

2. 使用@Generated注解(JPA 2.2+支持)

对于数据库生成的字段,用@Generated注解明确指定生成策略为INSERT时由数据库生成:

@Column(name = "created_on", updatable = false)
@Generated(value = GenerationTime.INSERT)
private Timestamp createdOn;

@Column(name = "created_by", updatable = false)
@Generated(value = GenerationTime.INSERT)
private String createdBy;

这个注解告诉JPA,这些字段的值由数据库在INSERT操作时生成,JPA不会在INSERT语句中包含它们,同时会在插入后获取生成的值。

3. 修正实体类的setter方法

你的实体类中setCreatedOn和setCreatedBy方法存在问题:没有接收参数,也无法给字段赋值。正确的setter写法应该是:

public void setCreatedOn(Timestamp createdOn) {
    this.createdOn = createdOn;
}

public void setCreatedBy(String createdBy) {
    this.createdBy = createdBy;
}

虽然这不是默认值不生效的直接原因,但修正后能确保JPA正确加载数据库生成的字段值到实体对象中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 03:50:46