1. 概述
在本教程中,我们将探讨在 JPA 中设置数据库列默认值的几种方式。
我们会介绍如何在实体类中直接设置默认值、通过数据库表定义设置默认值,以及使用 JPA 提供的注解和生命周期回调来实现默认值的设定。
2. 在实体类中设置默认值
最简单的方法是在实体类字段中直接赋值:
@Entity
public class User {
@Id
private Long id;
private String firstName = "John Snow";
private Integer age = 25;
private Boolean locked = false;
}
这样,每次通过 new
创建对象时,都会带上这些默认值:
@Test
void givenUser_whenUsingEntityValue_thenSavedWithDefaultValues() {
User user = new User();
user = userRepository.save(user);
assertEquals(user.getName(), "John Snow");
assertEquals(user.getAge(), 25);
assertFalse(user.getLocked());
}
✅ 优点:简单直接,无需数据库干预。
❌ 缺点:这些默认值不会反映在数据库表结构中,因此如果字段被设置为 null
,依然可以保存成功。
create table user
(
id bigint not null constraint user_pkey primary key,
name varchar(255),
age integer,
locked boolean
);
也就是说,即使我们显式设置为 null,也不会报错:
@Test
void givenUser_whenNameIsNull_thenSavedNameWithNullValue() {
User user = new User();
user.setName(null);
user.setAge(null);
user.setLocked(null);
user = userRepository.save(user);
assertNull(user.getName());
assertNull(user.getAge());
assertNull(user.getLocked());
}
⚠️ 所以,如果你希望数据库层面也强制默认值,这种方法并不合适。
3. 在数据库表定义中设置默认值
我们可以使用 @Column
注解的 columnDefinition
属性来指定列的默认值:
@Entity
public class User {
@Id
Long id;
@Column(columnDefinition = "varchar(255) default 'John Snow'")
private String name;
@Column(columnDefinition = "integer default 25")
private Integer age;
@Column(columnDefinition = "boolean default false")
private Boolean locked;
}
生成的数据库表结构如下:
create table user
(
id bigint not null constraint user_pkey primary key,
name varchar(255) default 'John Snow',
age integer default 25,
locked boolean default false
);
这样即使字段未赋值,保存时也会自动填充默认值:
@Test
void givenUser_whenUsingSQLDefault_thenSavedWithDefaultValues() {
User user = new User();
user = userRepository.save(user);
assertEquals(user.getName(), "John Snow");
assertEquals(user.getAge(), 25);
assertFalse(user.getLocked());
}
⚠️ 注意:使用这种方式后,首次保存实体时,不能将字段设置为 null,否则会违反数据库约束,具体行为取决于数据库配置。
4. 使用 @ColumnDefault
注解
Hibernate 提供了一个非标准但非常实用的注解 @ColumnDefault
,用于在 JPA 层面定义默认值,并反映在生成的 SQL 表结构中:
@Entity
@Table(name="users_entity")
public class UserEntity {
@Id
private Long id;
@ColumnDefault("John Snow")
private String name;
@ColumnDefault("25")
private Integer age;
@ColumnDefault("false")
private Boolean locked;
}
生成的建表语句如下:
create table users_entity
(
age integer default 25,
locked boolean default false,
id bigint not null,
name varchar(255) default 'John Snow',
primary key (id)
)
插入数据时,如果只传入 id
,其他字段将自动使用默认值:
INSERT INTO users_entity (id) VALUES (?);
void givenUser_whenSaveUsingQuery_thenSavedWithDefaultValues() {
EntityManager entityManager = // 初始化 entityManager
Query query = entityManager.createNativeQuery("INSERT INTO users_entity (id) VALUES(?) ");
query.setParameter(1, 2L);
query.executeUpdate();
user = userEntityRepository.find(2L);
assertEquals(user.getName(), "John Snow");
assertEquals(25, (int) user.getAge());
assertFalse(user.getLocked());
}
⚠️ 注意:如果插入语句包含了所有字段,而某些字段值为 null
,数据库不会自动应用默认值。也就是说,只有未显式包含的字段才会使用默认值。
5. 使用 @PrePersist
生命周期回调
如果你希望在 Java 层控制默认值,可以使用 @PrePersist
注解,在实体保存前自动设置默认值:
@Entity
public class UserEntity {
@Id
private Long id;
private String name;
private Integer age;
private Boolean locked;
@PrePersist
public void prePersist() {
if (name == null) {
name = "John Snow";
}
if (age == null) {
age = 25;
}
if (locked == null) {
locked = false;
}
}
}
✅ 优点:
- 不依赖数据库配置
- 可以进行更复杂的逻辑判断
- 即使字段被显式设为 null,也可以重新设置默认值
测试代码如下:
@Test
void givenUser_whenSaveUsingPrePersist_thenSavedWithDefaultValues() {
UserEntity user = new UserEntity();
userEntityRepository.save(user, 3L);
user = userEntityRepository.find(3L);
assertEquals(user.getName(), "John Snow");
assertEquals(25, (int) user.getAge());
assertFalse(user.getLocked());
}
⚠️ 缺点:需要手动编写逻辑,维护成本略高。
6. 总结
方法 | 是否反映在数据库 | 是否支持 null | 适用场景 |
---|---|---|---|
实体字段默认值 | ❌ | ✅ | 简单默认值,不依赖数据库 |
@Column(columnDefinition) |
✅ | ❌ | 需要数据库强制默认值 |
@ColumnDefault |
✅ | ❌ | JPA + 数据库联合控制 |
@PrePersist |
❌(可自定义) | ✅ | 复杂逻辑控制,或避免数据库依赖 |
根据你的业务需求和持久化策略,选择合适的方式设置默认值即可。