- Spring Boot JPA 教程
- Spring Boot JPA - 主页
- Spring Boot JPA - 概述
- Spring Boot JPA - 环境设置
- Spring Boot JPA - 架构
- Spring Boot JPA 与 Hibernate
- Spring Boot JPA - 应用程序设置
- Spring Boot JPA - 单元测试存储库
- Spring Boot JPA - 方法
- Spring Boot JPA - 自定义方法
- Spring Boot JPA - 命名查询
- Spring Boot JPA - 自定义查询
- Spring Boot JPA - 原生查询
- Spring Boot JPA 有用资源
- Spring Boot JPA - 快速指南
- Spring Boot JPA - 有用的资源
- Spring Boot JPA - 讨论
Spring Boot JPA - 快速指南
Spring Boot JPA - 概述
JPA是什么?
Java Persistence API 是 Oracle 公司提供的用于将大量数据持久存储到数据库中的类和方法的集合。
在哪里使用JPA?
为了减轻编写关系对象管理代码的负担,程序员遵循“JPA Provider”框架,该框架允许与数据库实例轻松交互。这里所需的框架由JPA接管。
JPA历史
EJB 的早期版本,使用 javax.ejb.EntityBean 接口定义了持久层与业务逻辑层相结合。
在引入 EJB 3.0 时,持久层被分离并指定为 JPA 1.0(Java Persistence API)。该 API 的规范与 JAVA EE5 的规范一起于 2006 年 5 月 11 日使用 JSR 220 发布。
JPA 2.0 与 JAVA EE6 规范一起于 2009 年 12 月 10 日作为 Java Community Process JSR 317 的一部分发布。
JPA 2.1 于 2013 年 4 月 22 日使用 JSR 338 与 JAVA EE7 规范一起发布。
JPA 提供商
JPA是一个开源API,因此各个企业供应商(例如Oracle、Redhat、Eclipse等)都通过在其中添加JPA持久化风味来提供新产品。其中一些产品包括 -
Hibernate、Eclipselink、Toplink、Spring Data JPA 等
Spring Boot JPA - 环境设置
本章将指导您如何准备开发环境以开始使用 Spring Boot 框架。它还将教您如何在设置 Spring Boot 框架之前在您的计算机上设置 JDK、Eclipse -
第 1 步 - 设置 Java 开发工具包 (JDK)
Java SE 可供免费下载。要下载,请单击此处,请下载与您的操作系统兼容的版本。
按照说明下载 Java,然后运行.exe以在您的计算机上安装 Java。在计算机上安装 Java 后,您需要设置环境变量以指向正确的安装目录。
设置 Windows 2000/XP 的路径
假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -
右键单击“我的电脑”并选择“属性”。
单击“高级”选项卡下的“环境变量”按钮。
现在,编辑“Path”变量并在其末尾添加 Java 可执行文件目录的路径。例如,如果路径当前设置为C:\Windows\System32,则按以下方式编辑它
C:\Windows\System32;c:\Program Files\java\jdk\bin。
设置Windows 95/98/ME的路径
假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -
编辑“C:\autoexec.bat”文件并在末尾添加以下行 -
设置路径=%PATH%;C:\Program Files\java\jdk\bin
设置 Linux、UNIX、Solaris、FreeBSD 的路径
应将环境变量 PATH 设置为指向 Java 二进制文件的安装位置。如果您在执行此操作时遇到问题,请参阅您的 shell 文档。
例如,如果您使用 bash 作为 shell,那么您可以在.bashrc末尾添加以下行-
导出 PATH=/path/to/java:$PATH'
或者,如果您使用集成开发环境 (IDE),如 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio,则必须编译并运行一个简单的程序来确认 IDE 知道您安装了 Java 的位置。否则,您将必须按照 IDE 文档中的规定进行正确的设置。
第 2 步 - 设置 Eclipse IDE
本教程中的所有示例都是使用 Eclipse IDE 编写的。因此,我们建议您应该在计算机上安装最新版本的 Eclipse。
要安装 Eclipse IDE,请从www.eclipse.org/downloads/下载最新的 Eclipse 二进制文件。下载安装后,将二进制发行版解压到一个方便的位置。例如,在 Windows 上的 C:\eclipse 中,或在 Linux/Unix 上的 /usr/local/eclipse 中,最后适当地设置 PATH 变量。
Eclipse 可以通过在 Windows 机器上执行以下命令来启动,或者只需双击 eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令来启动 Eclipse -
$/usr/local/eclipse/eclipse
成功启动后,如果一切正常,那么它应该显示以下结果 -
第 3 步 - 设置 m2eclipse
M2Eclipse 是 Eclipse 插件,它将 Apache Maven 集成到 Eclipse IDE 中非常有用。我们在本教程中使用 Maven 来构建 Spring Boot 项目,示例使用 m2eclipse 在 Eclipse 中运行。
使用 Eclipse IDE 中的“安装新软件”对话框安装最新的 M2Eclipse 版本,并将其指向此 p2 存储库 -
https://download.eclipse.org/technology/m2e/releases/latest/
第 3 步 - 设置 Spring Boot 项目
现在,如果一切正常,那么您可以继续设置 Spring Boot。以下是在您的计算机上下载并安装 Spring Boot 项目的简单步骤。
转到 spring 初始化程序链接来创建 spring boot 项目,https://start.spring.io/。
选择项目作为Maven Project。
选择语言为Java。
选择 Spring Boot 版本为2.5.3。
将项目元数据 - 组设置为com.tutorialspoint,工件设置为springboot-h2,名称设置为springboot-h2,描述设置为 Spring Boot 和 H2 数据库的演示项目,包名称设置为com.tutorialspoint.springboot-h2。
选择包装为Jar。
选择 java 作为11。
添加Spring Web、Spring Data JPA、H2 Database 和 Spring Boot DevTools等依赖项。
现在单击“生成”按钮生成项目结构。
下载基于maven的spring boot项目后,将maven项目导入到eclipse中,其余的eclipse将处理。它将下载 Maven 依赖项并构建项目,为进一步开发做好准备。
步骤 4 - 用于 REST API 测试的 POSTMAN
POSTMAN 是测试基于 REST 的 API 的有用工具。要安装 POSTMAN,请从www.postman.com/downloads/下载最新的 POSTMAN 二进制文件。下载可安装程序后,请按照说明进行安装和使用。
Spring Boot JPA - 架构
Java Persistence API 是将业务实体存储为关系实体的源。它展示了如何将 PLAIN OLD JAVA OBJECT (POJO) 定义为实体以及如何管理具有关系的实体。
类级架构
下图展示了JPA的类级架构。它展示了JPA的核心类和接口。
下表描述了上述架构中显示的每个单元。
| 先生编号 | 单位及说明 |
|---|---|
| 1 | 实体管理器工厂 这是EntityManager的工厂类。它创建并管理多个 EntityManager 实例。 |
| 2 | 实体管理器 它是一个接口,它管理对象的持久化操作。它的工作原理类似于查询实例的工厂。 |
| 3 | 实体 实体是持久性对象,作为记录存储在数据库中。 |
| 4 | 实体交易 它与EntityManager具有一对一的关系。对于每个 EntityManager,操作由 EntityTransaction 类维护。 |
| 5 | 坚持 此类包含获取 EntityManagerFactory 实例的静态方法。 |
| 6 | 询问 每个JPA供应商都实现这个接口来获取满足条件的关系对象。 |
上述类和接口用于将实体作为记录存储到数据库中。它们帮助程序员减少编写用于将数据存储到数据库中的代码的工作,以便他们可以专注于更重要的活动,例如编写用于将类与数据库表映射的代码。
JPA 类关系
在上面的架构中,类和接口之间的关系属于javax.persistence包。下图展示了它们之间的关系。
EntityManagerFactory 和 EntityManager 之间的关系是一对多的。它是 EntityManager 实例的工厂类。
EntityManager 和 EntityTransaction 之间的关系是一对一的。对于每个 EntityManager 操作,都有一个 EntityTransaction 实例。
EntityManager 和 Query 之间的关系是一对多的。使用一个 EntityManager 实例可以执行许多查询。
EntityManager 和 Entity 之间的关系是一对多的。一个EntityManager实例可以管理多个Entity。
Spring Boot JPA 与 Hibernate
日本PA
JPA 是一个规范,指定如何在 java 对象和关系数据库之间访问、管理和保存信息/数据。它提供了 ORM(对象关系映射)的标准方法。
Hibernate
Hibernate 是 JPA 的一个实现。它提供了一个轻量级框架,是最流行的 ORM 工具之一。
JPA 与 Hibernate
下表总结了 JPA 和 Hibernate 之间的差异。
| 类别 | 日本PA | Hibernate |
|---|---|---|
| 类型 | JPA 是一种规范,定义了使用 java 对象管理关系数据库数据的方式。 | Hibernate 是 JPA 的一个实现。它是一个 ORM 工具,用于将 java 对象持久保存到关系数据库中。 |
| 包裹 | JPA 使用 javax.persistence 包。 | Hibernate 使用 org.hibernate 包。 |
| 工厂 | JPA 使用 EntityManagerFactory 接口来获取实体管理器来持久化对象。 | Hibernate 使用 SessionFactory 接口来创建会话对象,然后使用该对象来持久化对象。 |
| 增删改查操作 | JPA使用EntityManager接口来创建/读取/删除操作并维护持久化上下文。 | Hibernate使用Session接口来创建/读取/删除操作并维护持久化上下文。 |
| 语言 | JPA 使用 JPQL(Java 持久性查询语言)作为数据库操作的面向对象查询语言。 | Hibernate 使用 HQL(Hibernate 查询语言)作为数据库操作的面向对象查询语言。 |
Spring Boot JPA - 应用程序设置
与上一章环境设置一样,我们在 eclipse 中导入了生成的 spring boot 项目。现在让我们在src/main/java文件夹中创建以下结构。
com.tutorialspoint.controller.EmployeeController - 基于 REST 的控制器,用于实现基于 REST 的 API。
com.tutorialspoint.entity.Employee - 表示数据库中相应表的实体类。
com.tutorialspoint.repository.EmployeeRepository - 用于在数据库上实现 CRUD 操作的存储库接口。
com.tutorialspoint.service.EmployeeService - 通过存储库功能实现业务操作的服务类。
com.tutorialspoint.springbooth2.SprintBootH2Application - Spring Boot 应用程序类。
SprintBootH2Application 类已经存在。我们需要创建上述包以及相关的类和接口,如下所示 -
实体-Entity.java
以下是 Employee 的默认代码。它代表一个包含 id、name、age 和 email 列的 Employee 表。
package com.tutorialspoint.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table
public class Employee {
@Id
@Column
private int id;
@Column
private String name;
@Column
private int age;
@Column
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
存储库-EmployeeRepository.java
以下是 Repository 对上述实体 Employee 实现 CRUD 操作的默认代码。
package com.tutorialspoint.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
}
服务-EmployeeService.java
以下是Service默认实现对repository函数操作的代码。
package com.tutorialspoint.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.repository.EmployeeRepository;
@Service
public class EmployeeService {
@Autowired
EmployeeRepository repository;
public Employee getEmployeeById(int id) {
return repository.findById(id).get();
}
public List<Employee> getAllEmployees(){
List<Employee> employees = new ArrayList<Employee>();
repository.findAll().forEach(employee -> employees.add(employee));
return employees;
}
public void saveOrUpdate(Employee employee) {
repository.save(employee);
}
public void deleteEmployeeById(int id) {
repository.deleteById(id);
}
}
控制器 - EmployeeController.java
以下是Controller实现REST API的默认代码。
package com.tutorialspoint.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.service.EmployeeService;
@RestController
@RequestMapping(path = "/emp")
public class EmployeeController {
@Autowired
EmployeeService employeeService;
@GetMapping("/employees")
public List<Employee> getAllEmployees(){
return employeeService.getAllEmployees();
}
@GetMapping("/employee/{id}")
public Employee getEmployee(@PathVariable("id") int id) {
return employeeService.getEmployeeById(id);
}
@DeleteMapping("/employee/{id}")
public void deleteEmployee(@PathVariable("id") int id) {
employeeService.deleteEmployeeById(id);
}
@PostMapping("/employee")
public void addEmployee(@RequestBody Employee employee) {
employeeService.saveOrUpdate(employee);
}
@PutMapping("/employee")
public void updateEmployee(@RequestBody Employee employee) {
employeeService.saveOrUpdate(employee);
}
}
应用程序 - SprintBootH2Application.java
以下是应用程序使用上述类的更新代码。
package com.tutorialspoint.sprintbooth2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@ComponentScan({"com.tutorialspoint.controller","com.tutorialspoint.service"})
@EntityScan("com.tutorialspoint.entity")
@EnableJpaRepositories("com.tutorialspoint.repository")
@SpringBootApplication
public class SprintBootH2Application {
public static void main(String[] args) {
SpringApplication.run(SprintBootH2Application.class, args);
}
}
运行/调试配置
在 Eclipse 中创建以下Maven 配置,以运行目标为spring-boot:run 的springboot 应用程序。此配置将有助于运行 REST API,我们可以使用 POSTMAN 测试它们。
运行应用程序
在 eclipse 中,运行Employee Application配置。Eclipse 控制台将显示类似的输出。
[INFO] Scanning for projects... ... 2021-07-24 20:51:14.823 INFO 9760 --- [restartedMain] c.t.s.SprintBootH2Application: Started SprintBootH2Application in 7.353 seconds (JVM running for 8.397)
服务器启动并运行后,首先使用 Postman 发出 POST 请求来添加记录。
在 POSTMAN 中设置以下参数。
HTTP 方法 - POST
URL - http://localhost:8080/emp/employee
BODY -员工 JSON
{
"id": "1",
"age": "35",
"name": "Julie",
"email": "julie@gmail.com"
}
单击发送按钮并检查响应状态是否正常。现在发出 GET 请求来获取所有记录。
在 POSTMAN 中设置以下参数。
HTTP 方法 - GET
URL - http://localhost:8080/emp/employees
单击发送按钮并验证响应。
[{
"id": "1",
"age": "35",
"name": "Julie",
"email": "julie@gmail.com"
}]
Spring Boot JPA - 单元测试存储库
要测试存储库,我们需要以下注释和类 -
@ExtendWith(SpringExtension.class) - 使用 SpringExtension 类标记要作为测试用例运行的类。
@SpringBootTest(classes = SprintBootH2Application.class) - 配置 Spring Boot 应用程序。
@Transactional - 标记存储库以执行 CRUD 操作。
@Autowired private EmployeeRepository employeeRepository - 要测试的 EmployeeRepository 对象。
例子
以下是EmployeeRepositoryTest的完整代码。
package com.tutorialspoint.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.sprintbooth2.SprintBootH2Application;
@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = SprintBootH2Application.class)
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@Test
public void testFindById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), result.getId());
}
@Test
public void testFindAll() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testSave() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee found = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), found.getId());
}
@Test
public void testDeleteById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
employeeRepository.deleteById(employee.getId());
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 0);
}
private Employee getEmployee() {
Employee employee = new Employee();
employee.setId(1);
employee.setName("Mahesh");
employee.setAge(30);
employee.setEmail("mahesh@test.com");
return employee;
}
}
运行测试用例
输出
在 eclipse 中右键单击该文件并选择“运行 JUnit 测试”并验证结果。
Spring Boot JPA - 存储库方法
现在让我们分析我们创建的存储库接口中可用的方法。
存储库-EmployeeRepository.java
以下是 Repository 对上述实体 Employee 实现 CRUD 操作的默认代码。
package com.tutorialspoint.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
}
现在这个存储库默认包含以下方法。
| 先生编号 | 方法及说明 |
|---|---|
| 1 | 计数():长 返回可用实体的数量。 |
| 2 | 删除(员工实体):void 删除一个实体。 |
| 3 | 全部删除():无效 删除所有实体。 |
| 4 | deleteAll(Iterable< 扩展 Employee > 实体):void 删除作为参数传递的实体。 |
| 5 | deleteAll(Iterable<extends Integer > ids):void 删除使用作为参数传递的 id 标识的实体。 |
| 6 | 存在ById(整数id):布尔值 使用其 id 检查实体是否存在。 |
| 7 | findAll():Iterable<员工> 返回所有实体。 |
| 8 | findAllByIds(Iterable< Integer > ids):Iterable< 员工 > 返回使用作为参数传递的 id 标识的所有实体。 |
| 9 | findById(Integer id):可选<员工> 返回使用 id 标识的实体。 |
| 10 | 保存(员工实体):员工 保存一个实体并返回更新后的实体。 |
| 11 | saveAll(Iterable< 员工> 实体): Iterable< 员工> 保存所有传递的实体并返回更新的实体。 |
Spring Boot JPA - 自定义方法
我们已经在JPA 方法章节的存储库中检查了默认可用的方法。现在让我们添加一个方法并测试它。
存储库-EmployeeRepository.java
例子
添加一种通过姓名查找员工的方法。
package com.tutorialspoint.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
public List<Employee> findByName(String name);
public List<Employee> findByAge(int age);
}
现在 Spring JPA 将自动创建上述方法的实现,因为我们遵循基于属性的命名法。让我们通过在测试文件中添加测试用例来测试添加的方法。下面文件的最后两个方法测试添加的自定义方法。
以下是EmployeeRepositoryTest的完整代码。
package com.tutorialspoint.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.sprintbooth2.SprintBootH2Application;
@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = SprintBootH2Application.class)
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@Test
public void testFindById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), result.getId());
}
@Test
public void testFindAll() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testSave() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee found = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), found.getId());
}
@Test
public void testDeleteById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
employeeRepository.deleteById(employee.getId());
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 0);
}
private Employee getEmployee() {
Employee employee = new Employee();
employee.setId(1);
employee.setName("Mahesh");
employee.setAge(30);
employee.setEmail("mahesh@test.com");
return employee;
}
@Test
public void testFindByName() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByAge() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
}
运行测试用例
输出
在 eclipse 中右键单击该文件并选择“运行 JUnit 测试”并验证结果。
Spring Boot JPA - 命名查询
有时会出现这样的情况,我们需要一个自定义查询来完成一个测试用例。我们可以使用@NamedQuery注释在实体类中指定命名查询,然后在存储库中声明该方法。下面是一个例子。
我们在JPA 自定义方法章节的存储库中添加了自定义方法。现在让我们使用 @NamedQuery 添加另一个方法并测试它。
实体-Entity.java
以下是 Employee 的默认代码。它代表一个包含 id、name、age 和 email 列的 Employee 表。
package com.tutorialspoint.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table
@NamedQuery(name = "Employee.findByEmail",
query = "select e from Employee e where e.email = ?1")
public class Employee {
@Id
@Column
private int id;
@Column
private String name;
@Column
private int age;
@Column
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
存储库-EmployeeRepository.java
添加一种按姓名和年龄查找员工的方法。
package com.tutorialspoint.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
public List<Employee> findByName(String name);
public List<Employee> findByAge(int age);
public Employee findByEmail(String email);
}
现在 Spring JPA 将使用命名查询中提供的查询自动创建上述方法的实现。让我们通过在测试文件中添加测试用例来测试添加的方法。下面文件的最后两个方法测试添加的命名查询方法。
以下是EmployeeRepositoryTest的完整代码。
package com.tutorialspoint.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.sprintbooth2.SprintBootH2Application;
@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = SprintBootH2Application.class)
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@Test
public void testFindById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), result.getId());
}
@Test
public void testFindAll() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testSave() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee found = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), found.getId());
}
@Test
public void testDeleteById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
employeeRepository.deleteById(employee.getId());
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 0);
}
private Employee getEmployee() {
Employee employee = new Employee();
employee.setId(1);
employee.setName("Mahesh");
employee.setAge(30);
employee.setEmail("mahesh@test.com");
return employee;
}
@Test
public void testFindByName() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByAge() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByEmail() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findByEmail(employee.getEmail());
assertNotNull(result);
}
}
运行测试用例
在 eclipse 中右键单击该文件并选择“运行 JUnit 测试”并验证结果。
Spring Boot JPA - 自定义查询
有时会出现这样的情况,我们需要一个自定义查询来完成一个测试用例。我们可以使用@Query注释来指定存储库中的查询。下面是一个例子。在此示例中,我们使用 JPQL(Java 持久性查询语言)。
我们在JPA 命名查询章节的存储库中添加了名称查询自定义方法。现在让我们使用 @Query 添加另一个方法并测试它。
存储库-EmployeeRepository.java
添加一种方法来获取按姓名排序的员工列表。
package com.tutorialspoint.repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
public List<Employee> findByName(String name);
public List<Employee> findByAge(int age);
public Employee findByEmail(String email);
@Query(value = "SELECT e FROM Employee e ORDER BY name")
public List<Employee> findAllSortedByName();
}
让我们通过在测试文件中添加测试用例来测试添加的方法。下面文件的最后两个方法测试添加的自定义查询方法。
以下是EmployeeRepositoryTest的完整代码。
package com.tutorialspoint.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.sprintbooth2.SprintBootH2Application;
@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = SprintBootH2Application.class)
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@Test
public void testFindById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), result.getId());
}
@Test
public void testFindAll() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testSave() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee found = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), found.getId());
}
@Test
public void testDeleteById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
employeeRepository.deleteById(employee.getId());
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 0);
}
private Employee getEmployee() {
Employee employee = new Employee();
employee.setId(1);
employee.setName("Mahesh");
employee.setAge(30);
employee.setEmail("mahesh@test.com");
return employee;
}
@Test
public void testFindByName() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByAge() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByEmail() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findByEmail(employee.getEmail());
assertNotNull(result);
}
@Test
public void testFindAllSortedByName() {
Employee employee = getEmployee();
Employee employee1 = new Employee();
employee1.setId(2);
employee1.setName("Aarav");
employee1.setAge(20);
employee1.setEmail("aarav@test.com");
employeeRepository.save(employee);
employeeRepository.save(employee1);
List<Employee> result = employeeRepository.findAllSortedByName();
assertEquals(employee1.getName(), result.get(0).getName());
}
}
运行测试用例
在 eclipse 中右键单击该文件并选择“运行 JUnit 测试”并验证结果。
Spring Boot JPA - 原生查询
有时会出现这样的情况,我们需要一个自定义的本机查询来完成一个测试用例。我们可以使用@Query注释来指定存储库中的查询。下面是一个例子。在本例中,我们使用本机查询,并在查询注释中设置属性nativeQuery = true以将查询标记为本机。
我们在JPA 自定义查询章节的存储库中添加了自定义方法。现在让我们使用本机查询添加另一个方法并测试它。
存储库-EmployeeRepository.java
添加一种方法来获取按姓名排序的员工列表。
package com.tutorialspoint.repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.tutorialspoint.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
public List<Employee> findByName(String name);
public List<Employee> findByAge(int age);
public Employee findByEmail(String email);
@Query(value = "SELECT e FROM Employee e ORDER BY name")
public List<Employee> findAllSortedByName();
@Query(value = "SELECT * FROM Employee ORDER BY name", nativeQuery = true)
public List<Employee> findAllSortedByNameUsingNative();
}
让我们通过在测试文件中添加测试用例来测试添加的方法。下面文件的最后两个方法测试添加的自定义查询方法。
例子
以下是EmployeeRepositoryTest的完整代码。
package com.tutorialspoint.repository;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.tutorialspoint.entity.Employee;
import com.tutorialspoint.sprintbooth2.SprintBootH2Application;
@ExtendWith(SpringExtension.class)
@Transactional
@SpringBootTest(classes = SprintBootH2Application.class)
public class EmployeeRepositoryTest {
@Autowired
private EmployeeRepository employeeRepository;
@Test
public void testFindById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), result.getId());
}
@Test
public void testFindAll() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testSave() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee found = employeeRepository.findById(employee.getId()).get();
assertEquals(employee.getId(), found.getId());
}
@Test
public void testDeleteById() {
Employee employee = getEmployee();
employeeRepository.save(employee);
employeeRepository.deleteById(employee.getId());
List<Employee> result = new ArrayList<>();
employeeRepository.findAll().forEach(e -> result.add(e));
assertEquals(result.size(), 0);
}
private Employee getEmployee() {
Employee employee = new Employee();
employee.setId(1);
employee.setName("Mahesh");
employee.setAge(30);
employee.setEmail("mahesh@test.com");
return employee;
}
@Test
public void testFindByName() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByName(employee.getName()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByAge() {
Employee employee = getEmployee();
employeeRepository.save(employee);
List<Employee> result = new ArrayList<>();
employeeRepository.findByAge(employee.getAge()).forEach(e -> result.add(e));
assertEquals(result.size(), 1);
}
@Test
public void testFindByEmail() {
Employee employee = getEmployee();
employeeRepository.save(employee);
Employee result = employeeRepository.findByEmail(employee.getEmail());
assertNotNull(result);
}
@Test
public void testFindAllSortedByName() {
Employee employee = getEmployee();
Employee employee1 = new Employee();
employee1.setId(2);
employee1.setName("Aarav");
employee1.setAge(20);
employee1.setEmail("aarav@test.com");
employeeRepository.save(employee);
employeeRepository.save(employee1);
List<Employee> result = employeeRepository.findAllSortedByName();
assertEquals(employee1.getName(), result.get(0).getName());
}
@Test
public void testFindAllSortedByNameUsingNative() {
Employee employee = getEmployee();
Employee employee1 = new Employee();
employee1.setId(2);
employee1.setName("Aarav");
employee1.setAge(20);
employee1.setEmail("aarav@test.com");
employeeRepository.save(employee);
employeeRepository.save(employee1);
List<Employee> result = employeeRepository.findAllSortedByNameUsingNative();
assertEquals(employee1.getName(), result.get(0).getName());
}
}
运行测试用例
输出
在 eclipse 中右键单击该文件并选择“运行 JUnit 测试”并验证结果。
