1. 简介

本文将带你了解 JPA 中实体的基本概念,以及常用的注解及其作用。这些注解可以帮助我们定义和定制实体类,使其与数据库表结构一一对应。

2. 实体(Entity)

在 JPA 中,实体本质上就是普通的 Java 对象(POJO),用于表示可以被持久化到数据库的数据。每个实体类对应一张数据库表,实体类的实例则对应表中的一行记录。

2.1 @Entity 注解

假设我们有一个表示学生信息的 POJO 类 Student,我们希望将其映射为数据库实体:

public class Student {
    // fields, getters and setters
}

为了让 JPA 能识别这个类为实体,我们需要使用 @Entity 注解:

@Entity
public class Student {
    // fields, getters and setters
}

默认情况下,实体名与类名相同。我们也可以通过 name 属性自定义实体名:

@Entity(name = "student")
public class Student {
    // fields, getters and setters
}

⚠️注意:JPA 实现框架(如 Hibernate)可能会对实体类进行子类化,因此实体类不能是 final 的

2.2 @Id@GeneratedValue 注解

每个 JPA 实体必须有一个主键来唯一标识该实体。我们使用 @Id 注解来定义主键字段。主键值可以由数据库自动生成,也可以手动设置。使用 @GeneratedValue 可以指定主键的生成策略。

JPA 支持以下四种主键生成策略:

  • AUTO:由 JPA 提供者自动选择
  • TABLE:使用数据库表模拟序列
  • SEQUENCE:使用数据库序列
  • IDENTITY:依赖数据库自增列

示例代码如下:

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    // getters and setters
}

⚠️注意:主键字段不能是 final 的,且实体类必须有无参构造函数。

2.3 @Table 注解

通常,数据库表名和实体类名并不一致。此时可以使用 @Table 注解来指定表名:

@Entity
@Table(name = "STUDENT")
public class Student {
    // fields, getters and setters
}

还可以通过 schema 属性指定数据库模式(schema):

@Entity
@Table(name = "STUDENT", schema = "SCHOOL")
public class Student {
    // fields, getters and setters
}

✅建议:在多模块或复杂项目中,使用 schema 可以更清晰地组织数据库结构。

2.4 @Column 注解

@Column 注解用于定义实体字段与数据库列之间的映射关系。它支持多个属性,如:

  • name:列名
  • length:长度
  • nullable:是否允许为空
  • unique:是否唯一

示例:

@Entity
@Table(name = "STUDENT")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "STUDENT_NAME", length = 50, nullable = false, unique = false)
    private String name;

    // other fields, getters and setters
}

如果没有使用 @Column,默认字段名将与数据库列名一致。

2.5 @Transient 注解

有时我们希望某个字段不被持久化到数据库中,这时可以使用 @Transient 注解。

例如,age 字段可能由 birthDate 推导而来,不需要保存在数据库中:

@Entity
@Table(name = "STUDENT")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "STUDENT_NAME", length = 50, nullable = false)
    private String name;

    @Transient
    private Integer age;

    // other fields, getters and setters
}

✅踩坑提醒:不要在 @Transient 字段上使用 @Column,否则会导致持久化异常。

2.6 @Temporal 注解

当字段是 java.util.Datejava.util.Calendar 类型时,需要使用 @Temporal 注解来指定时间精度类型:

@Temporal(TemporalType.DATE)
private Date birthDate;

支持的类型包括:

  • DATE:仅日期(yyyy-MM-dd)
  • TIME:仅时间(HH:mm:ss)
  • TIMESTAMP:日期+时间(yyyy-MM-dd HH:mm:ss)

⚠️注意:从 JPA 3.1 开始,推荐使用 java.time.LocalDateLocalDateTime 等新时间 API,无需再使用 @Temporal

2.7 @Enumerated 注解

如果实体字段是 Java 枚举类型,可以使用 @Enumerated 注解指定其存储方式:

public enum Gender {
    MALE, FEMALE
}
@Enumerated(EnumType.STRING)
private Gender gender;

支持的存储方式:

  • EnumType.ORDINAL:按枚举顺序存储为整数(默认)
  • EnumType.STRING:按枚举名称存储为字符串

✅建议:使用 EnumType.STRING 更直观,避免因枚举顺序变化导致数据错误。

3. 小结

本篇文章详细介绍了 JPA 实体的基本概念和常用注解,包括:

注解 用途
@Entity 标记一个类为 JPA 实体
@Id 定义主键
@GeneratedValue 指定主键生成策略
@Table 映射实体类与数据库表
@Column 定义字段与数据库列的映射
@Transient 标记非持久化字段
@Temporal 处理日期时间类型字段
@Enumerated 持久化枚举类型字段

掌握这些注解是使用 JPA 的基础,也是构建高质量数据访问层的关键。


原始标题:Defining JPA Entities | Baeldung