目录
一、一对一关联
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());
}
}