基础pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 <?xml version="1.0" encoding="UTF-8"?> <project xmlns ="http://maven.apache.org/POM/4.0.0" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <groupId > cn.idea360</groupId > <artifactId > jpa-demo</artifactId > <version > 0.0.1</version > <name > jpa-demo</name > <description > jpa-demo</description > <properties > <java.version > 1.8</java.version > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <project.reporting.outputEncoding > UTF-8</project.reporting.outputEncoding > <spring-boot.version > 2.6.13</spring-boot.version > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-jpa</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > com.h2database</groupId > <artifactId > h2</artifactId > <scope > runtime</scope > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies > <dependencyManagement > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-dependencies</artifactId > <version > ${spring-boot.version}</version > <type > pom</type > <scope > import</scope > </dependency > </dependencies > </dependencyManagement > <build > <plugins > <plugin > <groupId > org.apache.maven.plugins</groupId > <artifactId > maven-compiler-plugin</artifactId > <version > 3.8.1</version > <configuration > <source > 1.8</source > <target > 1.8</target > <encoding > UTF-8</encoding > </configuration > </plugin > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > <version > ${spring-boot.version}</version > <configuration > <mainClass > cn.idea360.jpa.JpaDemoApplication</mainClass > <skip > true</skip > </configuration > <executions > <execution > <id > repackage</id > <goals > <goal > repackage</goal > </goals > </execution > </executions > </plugin > </plugins > </build > </project >
配置文件application.properties
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 server.port =8080 spring.h2.console.settings.web-allow-others =true spring.h2.console.path =/h2-console spring.h2.console.enabled =true spring.h2.console.settings.trace =true spring.datasource.url =jdbc:h2:file:./data/jpa-h2 spring.datasource.username =san spring.datasource.password =spring.datasource.driver-class-name =org.h2.Driver spring.jpa.database-platform =org.hibernate.dialect.H2Dialect spring.jpa.show-sql =true spring.jpa.hibernate.ddl-auto =update
使用 @ManyToOne进行单向关联
场景:一个部门里有多个员工。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package cn.idea360.jpa.entity;import lombok.Data;import javax.persistence.*;import java.io.Serializable;@Data @Entity @Table(name = "hr_employee") public class Employee implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") private Integer employeeId; @Column(name = "employee_name") private String employeeName; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="departmentId") private Department department; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package cn.idea360.jpa.entity;import lombok.Data;import javax.persistence.*;import java.io.Serializable;@Data @Entity @Table(name = "hr_department") public class Department implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") private Integer departmentId; @Column(name = "department_name") private String departmentName; }
在这样的设定下, 是由Employee
维护对Department
的参考来维持多对一的关系,Department
并没有意识到Employee
的存在,而在存储时,由于设定了CascadeType.ALL
,所以直接存储Employee
实例时,所参考的Department
也会一并被存储。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package cn.idea360.jpa.repository;import cn.idea360.jpa.entity.Department;import cn.idea360.jpa.entity.Employee;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;import javax.transaction.Transactional;import java.util.Arrays;@Slf4j @SpringBootTest class EmployeeRepositoryTest { @Resource private DepartmentRepository departmentRepository; @Resource private EmployeeRepository employeeRepository; @Resource private ObjectMapper objectMapper; @Test @Transactional void addAndGetEmployee () throws Exception { Department department = new Department(); department.setDepartmentName("技术部" ); Employee employee1 = new Employee(); employee1.setEmployeeName("张三" ); employee1.setDepartment(department); Employee employee2 = new Employee(); employee2.setEmployeeName("李四" ); employee2.setDepartment(department); employeeRepository.saveAll(Arrays.asList(employee1, employee2)); Department department1 = departmentRepository.findById(1 ).get(); log.info("db department: {}" , objectMapper.writeValueAsString(department1)); Employee employee = employeeRepository.getById(2 ); log.info("db employee: {}" , objectMapper.writeValueAsString(employee)); } }
日志输出:
1 2 3 4 5 Hibernate: insert into hr_department (id, department_name) values (default, ?) Hibernate: insert into hr_employee (id, department_id, employee_name) values (default, ?, ?) Hibernate: insert into hr_employee (id, department_id, employee_name) values (default, ?, ?) 2023-06-11 13:36:19.592 INFO 35924 --- [ main] c.i.j.repository.EmployeeRepositoryTest : db department: {"departmentId":1,"departmentName":"技术部"} 2023-06-11 13:36:19.595 INFO 35924 --- [ main] c.i.j.repository.EmployeeRepositoryTest : db employee: {"employeeId":2,"employeeName":"李四","department":{"departmentId":1,"departmentName":"技术部"}}
使用 @OneToMany进行单向关联
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package cn.idea360.jpa.entity;import lombok.Data;import javax.persistence.*;import java.io.Serializable;import java.util.List;@Data @Entity @Table(name = "hr_department") public class Department implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") private Integer departmentId; @Column(name = "department_name") private String departmentName; @OneToMany(cascade = CascadeType.ALL) @JoinColumn(name = "department_id") private List<Employee> employees; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package cn.idea360.jpa.entity;import lombok.Data;import javax.persistence.*;import java.io.Serializable;@Data @Entity @Table(name = "hr_employee") public class Employee implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") private Integer employeeId; @Column(name = "employee_name") private String employeeName; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package cn.idea360.jpa.repository;import cn.idea360.jpa.entity.Department;import cn.idea360.jpa.entity.Employee;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.annotation.Rollback;import javax.annotation.Resource;import javax.transaction.Transactional;import java.util.Arrays;@Slf4j @SpringBootTest class EmployeeRepositoryTest { @Resource private DepartmentRepository departmentRepository; @Resource private EmployeeRepository employeeRepository; @Resource private ObjectMapper objectMapper; @Test @Transactional @Rollback(value = false) void addAndGetDepartment () throws Exception { Employee employee1 = new Employee(); employee1.setEmployeeName("张三" ); Employee employee2 = new Employee(); employee2.setEmployeeName("李四" ); Department department = new Department(); department.setDepartmentName("技术部" ); department.setEmployees(Arrays.asList(employee1, employee2)); departmentRepository.save(department); Department department1 = departmentRepository.findById(1 ).get(); log.info("db department: {}" , objectMapper.writeValueAsString(department1)); log.info("db department.employees: {}" , objectMapper.writeValueAsString(department1.getEmployees())); Employee employee = employeeRepository.getById(2 ); log.info("db employee: {}" , objectMapper.writeValueAsString(employee)); } }
输出
1 2 3 4 5 6 7 8 9 10 Hibernate: insert into hr_department (id, department_name) values (default, ?) Hibernate: insert into hr_employee (id, employee_name) values (default, ?) Hibernate: insert into hr_employee (id, employee_name) values (default, ?) Hibernate: select department0_.id as id1_0_0_, department0_.department_name as departme2_0_0_ from hr_department department0_ where department0_.id=? Hibernate: select employees0_.department_id as departme3_1_0_, employees0_.id as id1_1_0_, employees0_.id as id1_1_1_, employees0_.employee_name as employee2_1_1_ from hr_employee employees0_ where employees0_.department_id=? 2023-06-11 14:53:40.497 INFO 37827 --- [ main] c.i.j.repository.EmployeeRepositoryTest : db department: {"departmentId":1,"departmentName":"技术部","employees":[{"employeeId":1,"employeeName":"张三"},{"employeeId":2,"employeeName":"李四"}]} 2023-06-11 14:53:40.498 INFO 37827 --- [ main] c.i.j.repository.EmployeeRepositoryTest : db department.employees: [{"employeeId":1,"employeeName":"张三"},{"employeeId":2,"employeeName":"李四"}] 2023-06-11 14:53:40.500 INFO 37827 --- [ main] c.i.j.repository.EmployeeRepositoryTest : db employee: {"employeeId":2,"employeeName":"李四"} Hibernate: update hr_employee set department_id=? where id=? Hibernate: update hr_employee set department_id=? where id=?
@OneToMany和@ManyToOne同时使用:双向的关联
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package cn.idea360.jpa.entity;import lombok.Data;import javax.persistence.*;import java.io.Serializable;@Data @Entity @Table(name = "hr_employee") public class Employee implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") private Integer employeeId; @Column(name = "employee_name") private String employeeName; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="departmentId") private Department department; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package cn.idea360.jpa.entity;import lombok.Data;import javax.persistence.*;import java.io.Serializable;import java.util.List;@Data @Entity @Table(name = "hr_department") public class Department implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY) @Column(name = "id") private Integer departmentId; @Column(name = "department_name") private String departmentName; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) private List<Employee> employees; }
测试还有问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 package cn.idea360.jpa.repository;import cn.idea360.jpa.entity.Department;import cn.idea360.jpa.entity.Employee;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.extern.slf4j.Slf4j;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;import javax.annotation.Resource;import javax.transaction.Transactional;import java.util.Arrays;@Slf4j @SpringBootTest class EmployeeRepositoryTest { @Resource private DepartmentRepository departmentRepository; @Resource private EmployeeRepository employeeRepository; @Resource private ObjectMapper objectMapper; @Test @Transactional void addAndGetDepartment () throws Exception { Employee employee1 = new Employee(); employee1.setEmployeeName("张三" ); Employee employee2 = new Employee(); employee2.setEmployeeName("李四" ); Department department = new Department(); department.setDepartmentName("技术部" ); department.setEmployees(Arrays.asList(employee1, employee2)); departmentRepository.save(department); Department department1 = departmentRepository.findById(1 ).get(); log.info("db department: {}" , objectMapper.writeValueAsString(department1)); log.info("db department.employees: {}" , objectMapper.writeValueAsString(department1.getEmployees())); Employee employee = employeeRepository.getById(2 ); log.info("db employee: {}" , objectMapper.writeValueAsString(employee)); } @Test @Transactional void addAndGetEmployee () throws Exception { Department department = new Department(); department.setDepartmentName("技术部" ); Employee employee1 = new Employee(); employee1.setEmployeeName("张三" ); employee1.setDepartment(department); Employee employee2 = new Employee(); employee2.setEmployeeName("李四" ); employee2.setDepartment(department); employeeRepository.saveAll(Arrays.asList(employee1, employee2)); Department department1 = departmentRepository.findById(1 ).get(); log.info("db department: {}" , objectMapper.writeValueAsString(department1)); log.info("db department.employees: {}" , objectMapper.writeValueAsString(department1.getEmployees())); Employee employee = employeeRepository.getById(2 ); log.info("db employee: {}" , objectMapper.writeValueAsString(employee)); } }
参考