Spring Data Jpa之JAP注解+多表设计

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);
        }
    }

查询结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值