SpringBoot简单使用JPA

基础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
# 应用服务 WEB 访问端口
server.port=8080
#************H2 Begin****************
##创建表的MySql语句位置
#spring.datasource.schema=classpath:schema.sql
##插入数据的MySql语句的位置
#spring.datasource.data=classpath:data.sql
#remote visit
spring.h2.console.settings.web-allow-others=true
#console url。Spring启动后,可以访问 http://127.0.0.1:8080/h2-console 查看数据库
spring.h2.console.path=/h2-console
#default true。咱也可以用命令行访问好数据库,感兴趣的同学点这个链接 http://www.h2database.com/html/tutorial.html?highlight=Mac&search=mac#firstFound
spring.h2.console.enabled=true
spring.h2.console.settings.trace=true
#指定数据库的种类,这里 file意思是文件型数据库
spring.datasource.url=jdbc:h2:file:./data/jpa-h2
#用户名密码不需要改,都是临时值
spring.datasource.username=san
spring.datasource.password=
#指定Driver,有了Driver才能访问数据库
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;

/**
* @author cuishiying
*/
@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;

/**
* @author cuishiying
*/
@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;

/**
* @author cuishiying
*/
@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会生成中间表
@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;

/**
* @author cuishiying
*/
@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));
// FetchType.LAZY使用
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;

/**
* @author cuishiying
*/
@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;

/**
* @author cuishiying
*/
@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));
// FetchType.LAZY使用
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));
// FetchType.LAZY使用
log.info("db department.employees: {}", objectMapper.writeValueAsString(department1.getEmployees()));

Employee employee = employeeRepository.getById(2);
log.info("db employee: {}", objectMapper.writeValueAsString(employee));
}
}

参考