SpringData JPA 多表关联操作 (四)

目录

一、一对一关联

1、实体类

 2、数据操作层

3、测试

二、一对多

1、实体类

2、数据操作层

3、测试

三、多对一

1、实体类

2、数据操作层

3、测试

四、多对多

1、实体类

2、数据操作层

3、测试


本章节在案例(二)的基础上进行

一、一对一关联

1、实体类

主表:

package com.dragonwu.entity;


import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

/**
 * @author DragonWu
 * @date 2022-09-20 11:17
 **/
@Entity //作为hibernate的实体类
@Table(name="tb_customer")//映射的表名
public class Customer {

    /**
     * @Id 主键声明
     * @GeneratedValue: 配置主键的生成策略
     *      strategy
     *          GenerationType.IDENTITY: 自增,mysql
     *              *底层数据库必须支持自动增长
     *          GenerationType.SEQUENCE: 序列oracle
     *              *底层数据库必须支持序列
     *          GenerationType.TABLE: jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键
     *          GenerationType.AUTO: 由程序自动地帮助我们选择主键生成策略
     * @Cloumn 配置属性和表字段的映射关系
     *      name: 数据库表中字段的名称
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id",length = 20)
    private Long id;

    @Column(name="cus_name",columnDefinition = "varchar(32) default null comment '客户名'")
    private String name;//客户名

    @Column(name="cus_address",length = 200)
    private String address;//客户地址

    //单向关联 一对一
    /**
     * cascade 设置关联操作
     *  ALL 所有持久化操作
     *  PERSIST  只有插入才会执行关联操作
     *  MERGE   只有修改才会执行关联操作
     *  REMOVE   只有删除才会执行关联操作
     *
     *  fetch 设置是否懒加载
     *  默认 EAGER 立即加载
     *      LAZY 懒加载(直到用到对象才会进行查询,因为不是所有的关联对象,都需要用到)
     *
     *  orphanRemoval 关联移除 (通常在修改的时候会用到)
     *      一旦吧关联的数据设置null,或者修改为其他的关联数据,
     *      如果想删除关联数据,就可以设置true
     *
     *  optional 用来限制关联对象不能为null
     *      默认为true  可以为null
     *      false 不能为null
     */
    @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,optional = true)
    //设置外键字段名
    @JoinColumn(name="account_id")
    private Account account;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", account=" + account +
                '}';
    }
}

从表:

package com.dragonwu.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author DragonWu
 * @date 2022-09-23 10:28
 **/
@Entity
@Table(name = "tb_account")
@Data
public class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 32)
    private String username;

    @Column(length = 32)
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

这里的重点就是配置外键属性:

 2、数据操作层

package com.dragonwu.repositories;

import com.dragonwu.entity.Customer;
import org.springframework.data.repository.CrudRepository;

/**
 * @author DragonWu
 * @date 2022-09-21 10:33
 **/
public interface CustomerRepository extends CrudRepository<Customer,Long>{

}

3、测试

package com.dragonwu;

import com.dragonwu.entity.Account;
import com.dragonwu.entity.Customer;
import com.dragonwu.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

/**
 * @author DragonWu
 * @date 2022-09-23 10:39
 **/
@SpringBootTest(classes = App.class)
@RunWith(SpringRunner.class)
public class OneToOneTest {

    @Autowired
    private CustomerRepository customerRepository;

    //插入
    @Test
    public void testC(){
        //初始化数据
        Account account=new Account();
        account.setUsername("DragonWu");
        account.setPassword("123456");

        Customer customer = new Customer();
        customer.setAccount(account);
        customer.setName("龘龘");

        customerRepository.save(customer);
    }
    //懒加载查询
    @Test
    //为什么懒加载要配置事务
    //当通过repository调用完查询方法,session就会立即关闭,一旦session关闭你就不能查询
    //加了事务后,就能让session直到事务方法执行完毕后才会关闭
    @Transactional(readOnly = true)
    public void testR_lazy(){
        Optional<Customer> customer = customerRepository.findById(12L);//只查询出客户表,session关闭
        System.out.println("===================");
        System.out.println(customer.get());//toString
    }

    //删除
    @Test
    public void testD(){
        customerRepository.deleteById(12L);//当开启删除同时操作从表时,外键表对应的数据也会被删除
    }

    //更新
    @Test
    public void testU(){
        Customer customer = new Customer();
        customer.setId(12L);
        customer.setName("Dragon");
        customer.setAccount(null);
        customerRepository.save(customer);
    }
}

新增运行后我们可以看到,自动生成表并插入数据如下

二、一对多

1、实体类

主表:

package com.dragonwu.entity;


import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import java.util.List;

/**
 * @author DragonWu
 * @date 2022-09-20 11:17
 **/
@Entity //作为hibernate的实体类
@Table(name="tb_customer")//映射的表名
public class Customer {

    /**
     * @Id 主键声明
     * @GeneratedValue: 配置主键的生成策略
     *      strategy
     *          GenerationType.IDENTITY: 自增,mysql
     *              *底层数据库必须支持自动增长
     *          GenerationType.SEQUENCE: 序列oracle
     *              *底层数据库必须支持序列
     *          GenerationType.TABLE: jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键
     *          GenerationType.AUTO: 由程序自动地帮助我们选择主键生成策略
     * @Cloumn 配置属性和表字段的映射关系
     *      name: 数据库表中字段的名称
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id",length = 20)
    private Long id;

    @Column(name="cus_name",columnDefinition = "varchar(32) default null comment '客户名'")
    private String name;//客户名

    @Column(name="cus_address",length = 200)
    private String address;//客户地址

    //单向关联 一对一
    /**
     * cascade 设置关联操作
     *  ALL 所有持久化操作
     *  PERSIST  只有插入才会执行关联操作
     *  MERGE   只有修改才会执行关联操作
     *  REMOVE   只有删除才会执行关联操作
     *
     *  fetch 设置是否懒加载
     *  默认 EAGER 立即加载
     *      LAZY 懒加载(直到用到对象才会进行查询,因为不是所有的关联对象,都需要用到)
     *
     *  orphanRemoval 关联移除 (通常在修改的时候会用到)
     *      一旦吧关联的数据设置null,或者修改为其他的关联数据,
     *      如果想删除关联数据,就可以设置true
     *
     *  optional 用来限制关联对象不能为null
     *      默认为true  可以为null
     *      false 不能为null
     */
    @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,optional = true)
    //设置外键字段名
    @JoinColumn(name="account_id")
    private Account account;

    //一对多
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="customer_id")
    private List<Message> messages;

    public List<Message> getMessages() {
        return messages;
    }

    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", account=" + account +
                '}';
    }
}

从表:

package com.dragonwu.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author DragonWu
 * @date 2022-09-23 17:53
 **/
@Entity
@Table(name="tb_message")
public class Message {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 255)
    private String info;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public Message(String info) {
        this.info = info;
    }

    public Message() {
    }
}

与一对一类似,不过特殊的是从表的外键写到了主表的类里了。其他属性参考一对一。 

2、数据操作层

依然为之前数据操作层的代码

3、测试

package com.dragonwu;

import com.dragonwu.entity.Customer;
import com.dragonwu.entity.Message;
import com.dragonwu.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author DragonWu
 * @date 2022-09-23 18:01
 **/
@SpringBootTest(classes = App.class)
@RunWith(SpringRunner.class)
public class OneToManyTest {

    @Autowired
    private CustomerRepository customerRepository;

    //插入
    @Test
    public void testC(){
        List<Message> messageList=new ArrayList<>();
        messageList.add(new Message("test1"));
        messageList.add(new Message("test2"));
        messageList.add(new Message("test3"));

        Customer customer = new Customer();
        customer.setName("龘龘");
        customer.setMessages(messageList);

        customerRepository.save(customer);
    }

    @Test
    @Transactional(readOnly = true)//多对多时默认为懒加载,必须要加事务
    public void testR(){
        Optional<Customer> byId = customerRepository.findById(15L);
        System.out.println("====================");
        System.out.println(byId);
    }

}

可以看到数据已经创建成功:

三、多对一

对应一对多的写法,我们写可以单独写多对一的注解来声明。

但对于性能来说,我们应该首选多对一。

1、实体类

package com.dragonwu.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * @author DragonWu
 * @date 2022-09-23 17:53
 **/
@Entity
@Table(name="tb_message")
public class Message {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(length = 255)
    private String info;

    //多对一
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "customer_id")
    private Customer customer;

    public Customer getCustomer() {
        return customer;
    }

    public Message(String info, Customer customer) {
        this.info = info;
        this.customer = customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    public Message(String info) {
        this.info = info;
    }

    public Message() {
    }
}

2、数据操作层

package com.dragonwu.repositories;

import com.dragonwu.entity.Message;
import org.springframework.data.repository.CrudRepository;

/**
 * @author DragonWu
 * @date 2022-09-23 18:37
 **/
public interface MessageRepository extends CrudRepository<Message, Long> {
}

3、测试

package com.dragonwu;

import com.dragonwu.entity.Customer;
import com.dragonwu.entity.Message;
import com.dragonwu.repositories.MessageRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * @author DragonWu
 * @date 2022-09-23 18:40
 **/
@SpringBootTest(classes = App.class)
@RunWith(SpringRunner.class)
public class ManyToOneTest {

    @Autowired
    private MessageRepository repository;

    @Test
    public void testC(){
        //一
        Customer customer = new Customer();
        customer.setName("Jack");

        //多
        List<Message> list=new ArrayList<>();
        list.add(new Message("你哈",customer));
        list.add(new Message("hello",customer));

        repository.saveAll(list);
    }
}

四、多对多

1、实体类

客户表:

package com.dragonwu.entity;


import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import java.util.List;

/**
 * @author DragonWu
 * @date 2022-09-20 11:17
 **/
@Entity //作为hibernate的实体类
@Table(name="tb_customer")//映射的表名
public class Customer {

    /**
     * @Id 主键声明
     * @GeneratedValue: 配置主键的生成策略
     *      strategy
     *          GenerationType.IDENTITY: 自增,mysql
     *              *底层数据库必须支持自动增长
     *          GenerationType.SEQUENCE: 序列oracle
     *              *底层数据库必须支持序列
     *          GenerationType.TABLE: jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键
     *          GenerationType.AUTO: 由程序自动地帮助我们选择主键生成策略
     * @Cloumn 配置属性和表字段的映射关系
     *      name: 数据库表中字段的名称
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id",length = 20)
    private Long id;

    @Column(name="cus_name",columnDefinition = "varchar(32) default null comment '客户名'")
    private String name;//客户名

    @Column(name="cus_address",length = 200)
    private String address;//客户地址

    //单向关联 一对一
    /**
     * cascade 设置关联操作
     *  ALL 所有持久化操作
     *  PERSIST  只有插入才会执行关联操作
     *  MERGE   只有修改才会执行关联操作
     *  REMOVE   只有删除才会执行关联操作
     *
     *  fetch 设置是否懒加载
     *  默认 EAGER 立即加载
     *      LAZY 懒加载(直到用到对象才会进行查询,因为不是所有的关联对象,都需要用到)
     *
     *  orphanRemoval 关联移除 (通常在修改的时候会用到)
     *      一旦吧关联的数据设置null,或者修改为其他的关联数据,
     *      如果想删除关联数据,就可以设置true
     *
     *  optional 用来限制关联对象不能为null
     *      默认为true  可以为null
     *      false 不能为null
     */
    @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY,orphanRemoval = true,optional = true)
    //设置外键字段名
    @JoinColumn(name="account_id")
    private Account account;

    //一对多
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name="customer_id")
    private List<Message> messages;

    //单向多对多
    @ManyToMany(cascade = CascadeType.ALL)
    //中间表需要通过JoinTable来维护外键:(不设置也会自动生成)
    /*
    name 指定中间表名称
    joinColumns  设置本表的外键名称
    inverseJoinColumns   设置关联表的外键名称
     */
    @JoinTable(
            name = "tb_customer_role_relation",  //中间表的名字
            joinColumns = {@JoinColumn(name="c_id")}, //关联的外键
            inverseJoinColumns = {@JoinColumn(name = "r_id")}//关联表对应的外键
    )
    private List<Role> roles;

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public List<Message> getMessages() {
        return messages;
    }

    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", account=" + account +
                '}';
    }
}

权限表:

package com.dragonwu.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author DragonWu
 * @date 2022-09-24 9:40
 **/
@Entity
@Table(name = "tb_role")
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "role_name",length = 32)
    private String rName;

    public Role() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getrName() {
        return rName;
    }

    public void setrName(String rName) {
        this.rName = rName;
    }

    public Role(String rName) {
        this.rName = rName;
    }

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", rName='" + rName + '\'' +
                '}';
    }
}

2、数据操作层

依然使用之前的

3、测试

package com.dragonwu;

import com.dragonwu.entity.Customer;
import com.dragonwu.entity.Role;
import com.dragonwu.repositories.CustomerRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Commit;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author DragonWu
 * @date 2022-09-24 9:50
 **/
@SpringBootTest(classes = App.class)
@RunWith(SpringRunner.class)
public class ManyToMany {

    @Autowired
    private CustomerRepository customerRepository;

    @Test
    //保存
    public void testC() {
        List<Role> roles = new ArrayList<>();
        roles.add(new Role("超级管理员"));
        roles.add(new Role("商品管理员"));

        Customer customer = new Customer();
        customer.setName("Jack船长");
        customer.setRoles(roles);

        customerRepository.save(customer);
    }

    @Test
    @Transactional(readOnly = true)
    public void testR(){
        System.out.println(customerRepository.findById(20L));
    }

    /**
     * 注意加上
     * @Transactional
     * 若为单元测试还需加上@Commit注解
     *
     * 多对多其实不适合删除,因为经常出现数据可能会引用另一端
     * 此时删除就会出现异常
     * 要删除需要保证数据没有其他关联
     */
    @Test
    @Transactional
    @Commit
    public void testD(){
        Optional<Customer> byId = customerRepository.findById(18L);
        customerRepository.delete(byId.get());
    }
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值