如何使用Hibernate设置实体属性的默认值

178

如何在Hibernate字段中设置默认值?


3
你是使用XML配置文件还是注解? - Bruno
2
下面的答案只提供了JPA解决方案,这是正确的,但是如果要使用Hibernate解决方案,请参见https://dev59.com/vV4c5IYBdhLWcg3wSIgs,您必须使用`@ColumnDefault`。 - pdem
18个回答

215

如果您想设置真正的数据库默认值,请使用columnDefinition

@Column(name = "myColumn", nullable = false, columnDefinition = "int default 100") 

请注意,columnDefinition 中的字符串是依赖于数据库的。如果选择此选项,则必须使用 dynamic-insert,这样 Hibernate 在插入时不会包含具有 null 值的列。否则,谈论默认值是无关紧要的。

但是,如果您不想使用数据库默认值,而只是在 Java 代码中设置一个默认值,请像这样初始化您的变量 - private Integer myColumn = 100;


6
带注释的翻译:@org.hibernate.annotations.Entity(dynamicInsert = true) - homaxto
12
目前 org.hibernate.annotations.Entity 已经被标注为废弃。应该使用 @DynamicInsert 注解来代替它。 - jannis
3
针对这种情况,我不建议使用 columnDefinition,因为它在数据库之间不具备可移植性,而且你需要了解你所用服务器的具体 SQL 语言。 - pdem
1
需要在数据库的POJO类上添加@DynamicInsert。 - Reaz Murshed
6
建议使用@ColumnDefault而不是columnDefinition,因为它更独立于数据库。 - jalsh
请注意,这取决于hibernate.hbm2ddl.auto hibernate定义。如果设置为“CREATE”注释columnDefinition仅在创建数据库时使用,如果您的数据库已经创建,则不会发生任何更改。 - pikimota

66

使用Hibernate注解。

@ColumnDefault("-1")
private Long clientId;

如果已经存在表格,请重新创建以使更改生效。


1
谢谢,它有效了。但我不得不重新创建表格。 - Yamashiro Rion
6
我认为这应该是真正的解决方案,使用当前答案提出的columnDefinition非常麻烦,而且你必须包含类型。在我看来,注释@ColumnDefault要容易得多。 - judos
1
注意:只有在使用 hibernate.hbm2ddl.auto 让 Hibernate 自动创建/更新数据库模式时,@ColumnDefault 才有用。如果您不使用此自动生成模式功能,则它将没有任何效果。 - jumping_monkey
此解决方案还具有可移植性:MySQL,pgSQL。 - fdaugan

39
你可以使用@PrePersist注释,并在预持久化阶段设置默认值。

像这样:

//... some code
private String myProperty;
//... some code

@PrePersist
public void prePersist() {
    if(myProperty == null) //We set default value in case if the value is not set yet.
        myProperty = "Default value";
}

// property methods
@Column(nullable = false) //restricting Null value on database level.
public String getMyProperty() {
    return myProperty;
}

public void setMyProperty(String myProperty) {
    this.myProperty= myProperty;
}

这种方法不依赖于 Hibernate 下面的数据库类型/版本。默认值在持久化映射对象之前设置。


既然你的示例中没有使用setMyProperty,为什么还要包含它呢? - EndermanAPM
我只是举了一个关于Hibernate注解的例子,用于标准Java属性(私有变量和公共get/set方法)。我注意到并纠正了一个错误...缺少set方法参数的String类型。 - dbricman

32

那么只是设置字段的默认值呢?

private String _foo = "default";

//property here
public String Foo

如果他们传递了一个值,那么它将被覆盖,否则,您将拥有一个默认值。


9
默认值的作用不是防止更新值,对吗? - Janusz Lenar

19

默认实体属性值

如果您希望设置默认的实体属性值,则可以使用默认值初始化实体字段。

例如,您可以将默认的createdOn实体属性设置为当前时间,如下所示:

@Column(
    name = "created_on"
)
private LocalDateTime createdOn = LocalDateTime.now();

JPA中使用默认列值

如果您使用JPA和Hibernate生成DDL模式,尽管这不被推荐,但您可以使用JPA @Column注释的columnDefinition属性来设置默认列值,如下所示:

@Column(
    name = "created_on", 
    columnDefinition = "DATETIME(6) DEFAULT CURRENT_TIMESTAMP"
)
@Generated(GenerationTime.INSERT)
private LocalDateTime createdOn;

@Generated注解是必需的,因为我们想要指示Hibernate在持久化上下文被刷新后重新加载实体,否则,数据库生成的值将不会与内存中的实体状态同步。

与其使用columnDefinition,您最好使用类似Flyway的工具并使用DDL增量迁移脚本。这样,您将在脚本中设置DEFAULT SQL子句,而不是在JPA注释中。

使用Hibernate设置默认列值

如果您正在使用带有Hibernate的JPA,则还可以使用@ColumnDefault注释,例如:

@Column(name = "created_on")
@ColumnDefault(value="CURRENT_TIMESTAMP")
@Generated(GenerationTime.INSERT)
private LocalDateTime createdOn;

使用Hibernate设置默认的日期/时间列值

如果您正在使用JPA和Hibernate,并想要设置创建时间戳,则可以使用@CreationTimestamp注释来实现,如下所示:

@Column(name = "created_on")
@CreationTimestamp
private LocalDateTime createdOn;

完美,使用@Generated对我有用。但是使用@GeneratedValue会有什么区别? - Braian Coronel
1
@GeneratedValue 只能用于实体标识符。 - Vlad Mihalcea
@GeneratedValue 只适用于实体的主键,而 @Generated 适用于原始值。但是,如果一个子实体或外键有像 @OneToOne 这样的注释,我应该使用什么呢?因为这两个注释都对我来说不起作用。 - Braian Coronel
在使用H2内存数据库进行测试时,使用@Generated(GenerationTime.INSERT)会抛出org.springframework.orm.jpa.JpaSystemException: Lock mode not supported; nested exception is org.hibernate.UnsupportedLockAttemptException: Lock mode not supported异常。 - JavaLearner
@VladMihalcea 是否需要显式刷新以获取当前事务上下文中的当前默认值? - JavaLearner
显示剩余2条评论

8
如果您想在数据库中完成此操作:
在数据库中设置默认值(以SQL Server为例):
ALTER TABLE [TABLE_NAME] ADD  CONSTRAINT [CONSTRAINT_NAME]  DEFAULT (newid()) FOR [COLUMN_NAME]

映射 Hibernate 文件:

    <hibernate-mapping ....
    ...    
    <property name="fieldName" column="columnName" type="Guid" access="field" not-null="false"  insert="false" update="false"  />
    ...

看,关键在于 insert="false" update="false"。

Oracle存在一个问题:如果属性不为null,它的值仍然是默认值,而不是实际值。 - youngzy

6

一种解决方案是让您的getter检查您正在使用的任何值是否为null(或其未初始化状态),如果它等于该状态,则只需返回默认值:

public String getStringValue(){
     return (this.stringValue == null) ? "Default" : stringValue;
}

我正在使用一个调用实体对象setter的映射器。在getter和setter上都使用您的代码片段是否有不利影响? - Eric Francis
我正在使用Spring Boot,其中一个实体类中尝试使用以下代码:> private Long trianglesCount; @Column(name = "triangles_count") public Long getTrianglesCount() {如果这个trianglesCount是null的话,返回0L,否则返回trianglesCount。 } 默认情况下不会保存0L,而是将null保存在数据库中。 - Velmurugan A

5
使用@ColumnDefault()注释。这只适用于Hibernate。

4

在使用 Oracle 时,我尝试为枚举类型插入默认值。

我发现以下内容效果最佳。

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private EnumType myProperty = EnumType.DEFAULT_VALUE;

4

我搜索了一下,发现有很多关于列默认值的答案。如果您想使用在SQL表中定义的默认值,则在@Column注释中使用"insertable = false"。 insertable

@Column(name = columnName, length = lengthOfColumn, insertable = false)

如果您正在使用columnDefination和@Column注释,可能由于它是数据库相关的,它可能不起作用。


这在像“createdAt”这样的列上非常有效,您总是希望使用数据库默认值。谢谢! - Michal Filip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接