JPA注解主要解决什么?
JPA 注解主要是在告诉 Hibernate:
这个 Java 类对应什么表?
哪个字段对应哪个列?
谁是主键?
两张表什么关系?
保存前要做什么?
常见的JPA注解
第一组:定义"这个类对应数据库什么东西"
java
@Entity
@Table(name = "lesson")
public class Lesson {
}
@Entity 表示这个类是一个JPA实体类,要和数据库产生映射关系。
@Table 表示这个Java类映射到数据库的 lesson 表。如果不写@Table,JPA 通常会根据实体类名推断表名。
第二组:主键相关
java
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Id 表示数据库的主键
@GeneratedValue 表示ID 不由 Java 自己填写,让数据库生成。其中的strategy表示主键生成策略,GenerationType.IDENTITY表示生成策略为使用数据库自增主键。
第三组:数据库字段映射
java
@Column(nullable = false, length = 20, columnDefinition = "TEXT")
private String name;
@Column 表示name是数据库的一列,而且有这些++要求(括号里的属性设置)++。
java
@Column(nullable = false) //不能为空
@Column(unique = true) //数据库要求唯一
java
@Transient
private String displayName;
@Transient 表示这个字段只在 Java 中使用,不存进数据库。所以数据库中也就没有displayName这个列。可以理解为@Transient = 不持久化。
第四组:实体之间的关系
对象实体之间不是孤立的,数据库的表之间也是有联系的,为了表示这些联系,会使用以下注释。
@ManyToOne
例如一个学生可以有很多节课,但是一节 Lesson 只属于一个 Student(一对一课程)。
所以在Lesson类中,定义:
java
@ManyToOne
@JoinColumn(name = "student_id")
private Student student;
意思是很多 Lesson 可以指向同一个 Student。++Lesson(many) to Student (one)++
lesson通过student_id 这个外键与student表产生联系.
@JoinColumn
告诉JPA,student表与lesson表靠数据库里的那一列连接。在这个例子中,student与lesson两个表通过student_id连接
@OneToMany
一个学生对应多个课程
所以在Student类中,定义:
java
@OneToMany(mappedBy = "student")
private List<Lesson> lessons;
意思是一个Student有很多Lesson。 ++Student (one) to Lesson (many)++
@OneToOne
例如一节 Lesson 对应一份最终 Feedback
所以在Feedback类中,定义:
java
@OneToOne
@JoinColumn(name = "lesson_id")
private Lesson lesson;
意思是一节Lesson对应一个Feedback。Lesson (one)to Feedback (one)
@ManyToMany
例如一个老师可以教很多学生,一个学生也可以被很多老师教。
所以在Teacher类中,定义:
java
@ManyToMany
@joinColumn(name = "student_id")
private Teacher teacher;
意思是一个Teacher对应多个Student,一个Student对应多个Teacher。Teacher(many)to Student (many)。
java
@OneToMany(
mappedBy = "student",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<Lesson> lessons;
mappedBy 可以理解为真正维护这个关系的是 Lesson 类里的student字段。
也就是
java
class Lesson {
@ManyToOne
private Student student;
}
这里的student对象。
cascade意思大致是:对 Student 做某些数据库操作时,要不要连带影响它关联的 Lesson。
例如删除Student时,是否Lesson也跟着删除。这就是 cascade 涉及的问题。
常见参数:PERSIST 保存时连带保存
MERGE 更新时连带更新
REMOVE 删除时连带删除
ALL 全部
orphanRemoval大致表示:某个子对象从父对象关系中被移除后,要不要把数据库记录也删除。
fetch关系注解里经常:
java
@ManyToOne(fetch = FetchType.LAZY)
或者:
java
FetchType.EAGER
这是在控制:
关联的数据什么时候查。
例如查询 Lesson。
EAGER
查 Lesson 的同时:
Lesson
+
Student
一起查出来。
LAZY
先只查:
Lesson
等真的:
lesson.getStudent()
时再去查 Student。
可以简单记:
LAZY = 用到再查
EAGER = 一开始就查
第五组:字段类型
@Enumerated
项目中可能存在状态字段,表示某一对象或事物的状态。
例如反馈状态:
java
public enum FeedbackStatus {
DRAFT,
SUBMITTED
}
实体里:
java
@Enumerated(EnumType.STRING)
private FeedbackStatus status;
数据库可能存:
java
DRAFT
SUBMITTED
@Lob 用来表示比较大的文本或二进制数据。
例如:
java
@Lob
private String content;
过去经常用于大文本。
第六组:生命周期回调
java
@PrePersist
@PreUpdate
private void normalizeAndValidate() {
if (name != null) {
name = name.trim();
}
if (name == null || name.isEmpty() || name.length() > 20) {
throw new IllegalArgumentException("Student name must contain 1 to 20 characters");
}
if (notes != null && notes.length() > 200) {
throw new IllegalArgumentException("Student notes must not exceed 200 characters");
}
以上代码表示在插入和更改之前对学生姓名进行规范化检查。
@PrePersist
第一次 INSERT 数据库之前调用。
@PreUpdate
UPDATE 数据库之前调用。
类似还有:
java
@PostPersist 新增后
@PostUpdate 更新后
@PreRemove 删除前
@PostRemove 删除后
@PostLoad 查询加载后
@Version
乐观锁:在多人同时修改数据时会使用到。解决两个人同时修改一条数据,后提交的人会不会无意间覆盖前一个人的修改的问题。
其他Spring Data JPA注解
@Query
例如:
java
@Query("""
select s
from Student s
where s.grade = :grade
""")
List<Student> findByGrade(String grade);
表示:
默认 Repository 方法满足不了,我自己写查询。
JPA 不等于完全不能自己写查询。
@Query
例如:
java
@Query("""
select s
from Student s
where s.grade = :grade
""")
List<Student> findByGrade(
@Param("grade") String grade
);
负责:
把方法参数绑定到查询里的参数。
@Modifying
如果@Query不是 SELECT,而是:
java
UPDATE
DELETE
通常还会:
@Modifying
还有一类很重要,但不是 JPA 注解:校验 Jakarta Validation
java
@NotBlank
@Size(max = 20)
private String name;
@NotBlank : 不允许空字符串。
@Size(max = 20) : 最长 20。
@NotNull : 不能是 null。
还有:
java
@Min
@Max
@Email
@Pattern
以上注解负责Java层的数据校验,而像@Column(nullable = false)这种更多属于数据库映射和数据库约束。
Hibernate 注解
@Check 也是在加强数据约束。
Spring 事务
@Transactional
例如:
java
@Transactional
public void submitFeedback(...) {
saveFeedback();
updateLessonStatus();
}
意思:这几个数据库操作作为一个整体。保障操作完整执行,防止出现Feedback 已经保存,但Lesson 没更新的情况,有了事物,任何一步失败,整个操作回滚。