1、JPA注解的使用:
package com.example.jpademo.entity;
import javax.persistence.*;
@Entity//标记该类是一个实体类
//指定表名,当实体类名称与表名一致时,可以省略不写
@Table(name = "admin_user")
public class AdminUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
//设置实体类的属性名与表中的列表一一对应
//当实体类属性名与表中的列表一致时,可以省略不写
@Column(name = "age")
private Integer age;
private String address;
private String username;
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public AdminUser() {
}
public AdminUser(Integer id, Integer age, String address, String username, String test) {
this.id = id;
this.age = age;
this.address = address;
this.username = username;
this.test = test;
}
public AdminUser(Integer age, String address, String username, String test) {
this.age = age;
this.address = address;
this.username = username;
this.test = test;
}
@Override
public String toString() {
return "AdminUser{" +
"id=" + id +
", age=" + age +
", address='" + address + '\'' +
", username='" + username + '\'' +
", test='" + test + '\'' +
'}';
}
}
- @Entity:
用于定义对象将会成为被JPA管理的实体,将字段映射到指定的数据库表中,源码如下: - @Table:
用于指定数据库表名。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
//表的名字,可选。如果不填写,系统认为实体的名字和数据库表的名字一样
String name() default "";
//此表的目录,可选
String catalog() default "";
//此表的架构,可选
String schema() default "";
//唯一性约束,只有创建表的时候用,默认不需要
UniqueConstraint[] uniqueConstraints() default {};
//索引,只有创建表的时候使用,默认不需要
Index[] indexes() default {};
}
- @Id:
定义属性为数据库的主键,一个实体里面必须有一个,并且必须和@GeneratedValue配合使用和成对出现,源码如下:
@Target({ElementType.METHOD, public @interface Id { }
@GeneratedValue:
主键生成策略,源码如下:
public @interface GeneratedValue {
//Id的生成策略
GenerationType strategy() default GenerationType.AUTO;
/*通过Sequences(序列)生成Id,常见的是Oracle数据库ID生成规则,这个时候@SequenceGenerator使用:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)*/
String generator() default "";
}
GenerationType一共有以下四个属性:
public enum GenerationType {
//通过表产生主键,框架借由表模拟序列产生主键,使用该策略可以使用更易于数据库移植
TABLE,
//通过序列产生主键,通过@SequenceGenerator注解指定序列名,Mysql不支持这种方式
SEQUENCE,
//采用数据ID自增长,一般用于mysql数据库
IDENTITY,
//JPA自动选择合适的策略,是默认选项
AUTO;
private GenerationType() {
}
}
- @IdClass:
利用外部类的联合主键,源码:
public @interface IdClass {
//联合主键的类
Class value();
}
- @Basic:
表示属性是数据库表的字段的映射。如果实体的字段上没有任何注解,就默认为 @Basic,源码如下:
public @interface Basic {
//可选,EAGER(默认):立即加载;LAZY:延迟加载。(LAZY主要应用在大字段上面)
FetchType fetch() default FetchType.EAGER;
//可选。这个字段是否可以为null,默认是true
boolean optional() default true;
}
- @Transient:
Transient翻译为暂时的,表示该属性并非一个到数据库表的字段的映射,表示非持久化属性。JPA映射数据库的时候忽略它,不会将该属性映射为数据库表中的一个字段,与@Basic相反的作用 - @Column:
定义该属性对应数据库中的列名,源码如下:
public @interface Column {
String name() default "";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
int length() default 255;
int precision() default 0;
int scale() default 0;
}
2、多表设计:
- 表之间的关系划分:
由图可知,系统设计的三种实体关系分别为:多对多、一对多和一对一关系。注意:一对多关系可以看为两种:即一对多,多对一。 - JPA表关系分析步骤:
实现了ORM思想的框架中(入JPA),可以让我们通过操作实体类就可以实现对数据库表的操作,所以我们要在JPA的学习当中,掌握配置实体之间的关联关系。
第一步:首先确定两张表之间的关系,如果关系确定错了,后面做的所有操作都不可能正确。
第二步:在数据库中实现两张表的关系。
第三步:在实体类中描述出两个实体的关系
第四步:配置出实体类和数据库表的关系映射(重点)
关联关系注解
@OneToOne、@JoinColumn、@ManyToMany、@JoinTable、@OrderBy
- @JoinColumn定义外键关联的字段名称:
源码如下:
public @interface JoinColumn {
//目标表的字段名,必填
String name() default "";
//本实体的字段名,非必填,默认是本表ID
String referencedColumnName() default "";
//外键字段是否唯一
boolean unique() default false;
//外键字段是否允许为空
boolean nullable() default true;
//是否跟随一起新增
boolean insertable() default true;
//是否跟随一起更新
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
}
用法:@JoinColumn主要配合@OneToOne、@ManyToOne、@OneToMany一起使用,单独使用没有意义。
-
OneToOne一对一关联关系:
-
一对一操作:
需求:学生与班级的一对一关系
学生:一方
班级:一方
Student实体类:
@Entity
@Table(name = "t_student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String studentName;
@OneToOne(cascade = CascadeType.PERSIST)
//外键列
@JoinColumn(name = "grade_id")
private Grade grade;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
public Student() {
}
public Student(String studentName) {
this.studentName = studentName;
}
}
Grade实体类:
@Entity
@Table(name = "t_student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String studentName;
@OneToOne(cascade = CascadeType.PERSIST)
//外键列
@JoinColumn(name = "grade_id")
private Grade grade;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public Grade getGrade() {
return grade;
}
public void setGrade(Grade grade) {
this.grade = grade;
}
public Student() {
}
public Student(String studentName) {
this.studentName = studentName;
}
}
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
class Demo03ApplicationTests {
@Resource
private StudentRepository studentRepository;
/*
* 一对一添加:添加学生的同时添加年级
* */
@Test
void test() {
//创建年级
Grade grade=new Grade("s1");
//创建学生对象
Student student=new Student();
student.setStudentName("张玉梅");
student.setGrade(grade);//需要先创建年级
//保存学生
studentRepository.save(student);
}
}
测试结果:
- 一对一查询:
在上面一对一配置的基础之上进行查询即可:
@Test
void testSelect() {
Optional<Student>student=studentRepository.findById(1);
System.out.println(student);
System.out.println(student.get().getGrade());
}
查询结果如下:
- @OneToMany:
源码如下:
public @interface OneToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default FetchType.LAZY;
String mappedBy() default "";
boolean orphanRemoval() default false;
}
public @interface ManyToOne {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default FetchType.EAGER;
boolean optional() default true;
}
@ManyToOne与OneToMany的源码稍有区别仔细体会
- 一对多的关联关系:
需求:从角色到用户的一对多的关联关系
角色:一方
用户:多方 - 创建Users实体类:
1、多个用户拥有同一个角色(多对一)
2、toString()方法不添加Rolse属性
3、添加无参构造方法及带参(用户名,角色类型)构造方法
import javax.persistence.*;
@Entity
@Table(name = "t_user1")
public class User1 {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String userName;
//多个用户对应一个角色(多对一)
@ManyToOne
@JoinColumn(name = "role_id")
private Role role;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public User1() {
}
public User1(String userName) {
this.userName = userName;
}
}
- 创建Rolse实体类:
1、一个角色下有多个用户(一对多)
2、toString()方法不添加users属性
3、添加无参构造方法及带参(角色名称)构造方法
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "t_role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String roleName;
//一个角色被多个用户拥有
//fetch=FetchType.EAGER:立即加载
@OneToMany(mappedBy = "role",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Set<User1> users=new HashSet<User1>();
public Set<User1> getUsers() {
return users;
}
public void setUsers(Set<User1> users) {
this.users = users;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", roleName='" + roleName + '\'' +
'}';
}
public Role() {
}
public Role(String roleName) {
this.roleName = roleName;
}
}
接口:
```java
public interface RoleRepository extends JpaRepository<Role,Integer> {
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class RoleTest {
@Resource
RoleRepository roleRepository;
@Test
public void roleTest(){
Role role=new Role("管理员");
//创建两个用户
User1 user1=new User1("张三");
user1.setRole(role);
User1 user2=new User1("李四");
user2.setRole(role);
//设置关系
role.getUsers().add(user1);
role.getUsers().add(user2);
roleRepository.save(role);
}
}
结果:
- 一对多查询:
在上面一对多配置的基础之上查询即可:
/*
*查询某个角色下的用户列表
* */
@Test
public void testSelect(){
Optional<Role> role=roleRepository.findById(1);
System.out.println("该角色下的员工:");
for (User1 user1 : role.get().getUsers()) {
System.out.println(user1);
}
}
查询结果: