Spring Boot Jpa 简明教程
Spring Boot JPA - Overview
What is JPA?
Java 持久化 API 是一个类和方法的集合,用于将海量数据持久性地存储到由 Oracle Corporation 提供的数据库中。
Java Persistence API is a collection of classes and methods to persistently store the vast amounts of data into a database which is provided by the Oracle Corporation.
Where to use JPA?
为了减轻编写关系对象管理代码的负担,程序员遵循“JPA 提供程序”框架,该框架允许轻松与数据库实例进行交互。此处必需的框架由 JPA 接管。
To reduce the burden of writing codes for relational object management, a programmer follows the ‘JPA Provider’ framework, which allows easy interaction with database instance. Here the required framework is taken over by JPA.
JPA History
早期版本的 EJB 将持久性层与业务逻辑层结合在一起,使用 javax.ejb.EntityBean 接口定义。
Earlier versions of EJB, defined persistence layer combined with business logic layer using javax.ejb.EntityBean Interface.
-
While introducing EJB 3.0, the persistence layer was separated and specified as JPA 1.0 (Java Persistence API). The specifications of this API were released along with the specifications of JAVA EE5 on May 11, 2006 using JSR 220.
-
JPA 2.0 was released with the specifications of JAVA EE6 on December 10, 2009 as a part of Java Community Process JSR 317.
-
JPA 2.1 was released with the specification of JAVA EE7 on April 22, 2013 using JSR 338.
JPA Providers
JPA 是一个开源 API,因此,各种企业供应商(如 Oracle、Redhat、Eclipse 等)通过在其中添加 JPA 持久性风格来提供新产品。其中一些产品包括 -
JPA is an open source API, therefore various enterprise vendors such as Oracle, Redhat, Eclipse, etc. provide new products by adding the JPA persistence flavor in them. Some of these products include −
Hibernate, Eclipselink, Toplink, Spring Data JPA, etc.
Hibernate, Eclipselink, Toplink, Spring Data JPA, etc.
Spring Boot JPA - Environment Setup
本章将指导您如何准备开发环境,以便使用 Spring Boot Framework 开始您的工作。它还将教您在设置 Spring Boot Framework 之前如何设置机器上的 JDK、Eclipse -
This chapter will guide you on how to prepare a development environment to start your work with Spring Boot Framework. It will also teach you how to set up JDK, Eclipse on your machine before you set up Spring Boot Framework −
Step 1 - Setup Java Development Kit (JDK)
Java SE 可免费下载。若要下载 click here,请下载与你的操作系统兼容的版本。
Java SE is available for download for free. To download click here, please download a version compatible with your operating system.
按照说明下载 Java,并运行 .exe 在你的计算机上安装 Java。在计算机上安装 Java 后,你需要设置环境变量来指向正确的安装目录。
Follow the instructions to download Java, and run the .exe to install Java on your machine. Once you have installed Java on your machine, you would need to set environment variables to point to correct installation directories.
Setting Up the Path for Windows 2000/XP
假设你已将 Java 安装在 c:\Program Files\java\jdk 目录中 −
Assuming you have installed Java in c:\Program Files\java\jdk directory −
-
Right-click on 'My Computer' and select 'Properties'.
-
Click on the 'Environment variables' button under the 'Advanced' tab.
-
Now, edit the 'Path' variable and add the path to the Java executable directory at the end of it. For example, if the path is currently set to C:\Windows\System32, then edit it the following way C:\Windows\System32;c:\Program Files\java\jdk\bin.
Setting Up the Path for Windows 95/98/ME
假设你已将 Java 安装在 c:\Program Files\java\jdk 目录中 −
Assuming you have installed Java in c:\Program Files\java\jdk directory −
-
Edit the 'C:\autoexec.bat' file and add the following line at the end − SET PATH=%PATH%;C:\Program Files\java\jdk\bin
Setting Up the Path for Linux, UNIX, Solaris, FreeBSD
环境变量 PATH 应设置为指向已安装 Java 二进制文件的位置。如果你在这方面遇到问题,请参阅 shell 文档。
Environment variable PATH should be set to point to where the Java binaries have been installed. Refer to your shell documentation if you have trouble doing this.
例如,如果你使用 bash 作为你的 shell,那么你将在 .bashrc 的末尾添加以下行 −
For example, if you use bash as your shell, then you would add the following line at the end of your .bashrc −
或者,如果你使用诸如 Borland JBuilder、Eclipse、IntelliJ IDEA 或 Sun ONE Studio 这样的集成开发环境 (IDE),则必须编译并运行一个简单程序来确认 IDE 知道你在何处安装了 Java。否则,你必须按照 IDE 文档中给出的内容执行正确的设置。
Alternatively, if you use an Integrated Development Environment (IDE) like Borland JBuilder, Eclipse, IntelliJ IDEA, or Sun ONE Studio, you will have to compile and run a simple program to confirm that the IDE knows where you have installed Java. Otherwise, you will have to carry out a proper setup as given in the document of the IDE.
Step 2 - Setup Eclipse IDE
本教程中的所有示例都是使用 Eclipse IDE 编写的。因此,我们建议你应该在你机器上安装 Eclipse 的最新版本。
All the examples in this tutorial have been written using Eclipse IDE. So we would suggest you should have the latest version of Eclipse installed on your machine.
要安装 Eclipse IDE,请从 www.eclipse.org/downloads/ 下载最新的 Eclipse 二进制文件。下载安装文件后,将二进制分发解压缩到合适的目录中。例如,在 Windows 中的 C:\eclipse 或 Linux/Unix 中的 /usr/local/eclipse 中,最后适当设置 PATH 变量。
To install Eclipse IDE, download the latest Eclipse binaries from www.eclipse.org/downloads/. Once you download the installation, unpack the binary distribution into a convenient location. For example, in C:\eclipse on Windows, or /usr/local/eclipse on Linux/Unix and finally set PATH variable appropriately.
可以通过在 Windows 机器上执行以下命令启动 Eclipse,或者你只需双击 eclipse.exe
Eclipse can be started by executing the following commands on Windows machine, or you can simply double-click on eclipse.exe
%C:\eclipse\eclipse.exe
可以通过在 Unix(Solaris、Linux 等)机器上执行以下命令启动 Eclipse −
Eclipse can be started by executing the following commands on Unix (Solaris, Linux, etc.) machine −
$/usr/local/eclipse/eclipse
成功启动后,如果一切正常,它应该显示以下结果 −
After a successful startup, if everything is fine then it should display the following result −
Step 3 - Setup m2eclipse
M2Eclipse 是一个 Eclipse 插件,它对于将 Apache Maven 集成到 Eclipse IDE 中非常有用。我们在本教程中使用 maven 来构建 spring boot 项目,并使用 m2eclipse 在 eclipse 内运行示例。
M2Eclipse is eclipse plugin which is very useful integration for Apache Maven into the Eclipse IDE. We are using maven in this tutorial to build spring boot project and examples are run within eclipse using m2eclipse.
使用 Eclipse IDE 中的“安装新软件”对话框安装最新的 M2Eclipse 版本,并将其指向此 p2 仓库 -
Install the latest M2Eclipse release by using the Install New Software dialog in Eclipse IDE,and point it to this p2 repository −
Step 3 - Setup Spring Boot Project
现在,如果一切正常,则可以继续设置 Spring Boot。以下是下载和在机器上安装 Spring Boot 项目的简单步骤。
Now if everything is fine, then you can proceed to set up your Spring Boot. Following are the simple steps to download and install the Spring Boot Project on your machine.
-
Go to spring initializer link to create a spring boot project, https://start.spring.io/.
-
Select project as Maven Project.
-
Select language as Java.
-
Select Spring Boot version as 2.5.3.
-
Set Project Metadata - Group as com.tutorialspoint, Artifact as springboot-h2, name as springboot-h2, Description as Demo project for Spring Boot and H2 Database and package name as com.tutorialspoint.springboot-h2.
-
Select packaging as Jar.
-
Select java as 11.
-
Add dependencies as Spring Web, Spring Data JPA, H2 Database and Spring Boot DevTools.
现在点击生成按钮来生成项目结构。
Now click on GENERATE Button to generate the project structure.
一旦基于 maven 的 Spring Boot 项目下载完成,然后将 maven 项目导入 eclipse,其余操作由 eclipse 处理。它将下载 maven 依赖关系,并构建项目以使之可以进行进一步的开发。
Once the maven based spring boot project is downloaded, then import the maven project into eclipse and rest eclipse will handle. It will download the maven dependencies and build the project to make it ready for further development.
Step 4 - POSTMAN for REST APIs Testing
POSTMAN 是一款用来测试基于 REST 的 API 的有用工具。要安装 POSTMAN,可从 www.postman.com/downloads/ 下载最新的 POSTMAN 二进制文件。下载完可安装文件后,按照说明进行安装并使用。
POSTMAN is a useful tool to test REST Based APIs. To install POSTMAN, download the latest POSTMAN binaries from www.postman.com/downloads/. Once you download the installable, follow the instructions to install and use it.
Spring Boot JPA - Architecture
Java 持久化 API 是一个将业务实体存储为关系实体的源。它展示了如何将一个普通旧 Java 对象 (POJO) 定义为实体,以及如何通过关系管理实体。
Java Persistence API is a source to store business entities as relational entities. It shows how to define a PLAIN OLD JAVA OBJECT (POJO) as an entity and how to manage entities with relations.
Class Level Architecture
下图展示了 JPA 的类级架构。它展示了 JPA 的核心类和接口。
The following image shows the class level architecture of JPA. It shows the core classes and interfaces of JPA.
下表描述了上述架构中显示的每个单元。
The following table describes each of the units shown in the above architecture.
Sr.No |
Units & Description |
1 |
EntityManagerFactory This is a factory class of EntityManager. It creates and manages multiple EntityManager instances. |
2 |
EntityManager It is an Interface, it manages the persistence operations on objects. It works like factory for Query instance. |
3 |
Entity Entities are the persistence objects, stores as records in the database. |
4 |
EntityTransaction It has one-to-one relationship with EntityManager. For each EntityManager, operations are maintained by EntityTransaction class. |
5 |
Persistence This class contain static methods to obtain EntityManagerFactory instance. |
6 |
Query This interface is implemented by each JPA vendor to obtain relational objects that meet the criteria. |
上述类和接口用于将实体作为记录存储在数据库中。它们通过减少程序员为将数据存储到数据库中而编写代码的工作量来为他们提供帮助,以便他们可以专注于诸如编写映射类与数据库表的代码之类的更重要的活动。
The above classes and interfaces are used for storing entities into a database as a record. They help programmers by reducing their efforts to write codes for storing data into a database so that they can concentrate on more important activities such as writing codes for mapping the classes with database tables.
JPA Class Relationships
在上述架构中,类和接口之间的关系属于 javax.persistence 包。下图显示了它们之间的关系。
In the above architecture, the relations between the classes and interfaces belong to the javax.persistence package. The following diagram shows the relationship between them.
-
The relationship between EntityManagerFactory and EntityManager is one-to-many. It is a factory class to EntityManager instances.
-
The relationship between EntityManager and EntityTransaction is one-to-one. For each EntityManager operation, there is an EntityTransaction instance.
-
The relationship between EntityManager and Query is one-to-many. Many number of queries can execute using one EntityManager instance.
-
The relationship between EntityManager and Entity is one-to-many. One EntityManager instance can manage multiple Entities.
Spring Boot JPA vs Hibernate
JPA
JPA 是一个规范,它指定如何通过 Java 对象和关系数据库来访问、管理和持久化信息/数据。它为 ORM(对象关系映射)提供了一种标准方法。
JPA is a specification which specifies how to access, manage and persist information/data between java objects and relational databases. It provides a standard approach for ORM, Object Relational Mapping.
Hibernate
Hibernate 是 JPA 的一种实现。它提供了一个轻量级框架,并且是最流行的 ORM 工具之一。
Hibernate is an implementation of JPA. It provides a lightweight framework and is one of the most popular ORM tool used.
JPA Vs Hibernate
下表总结了 JPA 和 Hibernate 之间的差异。
Following table summerises the differences between JPA and Hibernate.
Category |
JPA |
Hibernate |
Type |
JPA is a specification and defines the way to manage relational database data using java objects. |
Hibernate is an implementation of JPA. It is an ORM tool to persist java objects into the relational databases. |
Package |
JPA uses javax.persistence package. |
Hibernate uses org.hibernate package. |
Factory |
JPA uses EntityManagerFactory interface to get the entity manager to persist objects. |
Hibernate uses SessionFactory interface to create session object which is then used to persist objects. |
CRUD Operations |
JPA uses EntityManager interface to create/read/delete operation and maintains the persistence context. |
Hibernate uses Session interface to create/read/delete operation and maintains the persistence context. |
Language |
JPA uses JPQL (Java Persistence Query Language) as Object Oriented Query language for database operations. |
Hibernate uses HQL (Hibernate Query Language) as Object Oriented Query language for database operations. |
Spring Boot JPA - Application Setup
与上一章 Environment Setup 中一样,我们已在 Eclipse 中导入了已生成的 Spring Boot 项目。现在,让我们在 src/main/java 文件夹中创建以下结构。
As in previous chapter Environment Setup, we’ve imported the generated spring boot project in eclipse. Now let’s create the following structure in src/main/java folder.
-
com.tutorialspoint.controller.EmployeeController − A REST Based Controller to implement REST based APIs.
-
com.tutorialspoint.entity.Employee − An entity class representing the corresponding table in database.
-
com.tutorialspoint.repository.EmployeeRepository − A Repository Interface to implement the CRUD operations on the database.
-
com.tutorialspoint.service.EmployeeService − A Service Class to implement the business opearations over repository functions.
-
com.tutorialspoint.springbooth2.SprintBootH2Application − A Spring Boot Application class.
SprintBootH2Application类已存在。我们须创建上述包和相关类和接口如下所示——
SprintBootH2Application class is already present. We need to create the above packages and relevant classes and interface as shown below −
Entity - Entity.java
以下为Employee的默认代码。它表示一个带id,name,age和email列的Employee表。
Following is the default code of Employee. It represents a Employee table with id, name, age and email columns.
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;
}
}
Repository - EmployeeRepository.java
以下为实现上述实体创建CRUD操作的存储库的默认代码,Employee。
Following is the default code of Repository to implement CRUD operations on above entity, Employee.
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> {
}
Service - EmployeeService.java
以下为实现库函数操作的服务的默认代码。
Following is the default code of Service to implement operations over repository functions.
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);
}
}
Controller - EmployeeController.java
以下为实现REST API的控制器的默认代码。
Following is the default code of Controller to implement REST APIs.
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);
}
}
Application - SprintBootH2Application.java
以下为用于使用上述类的Application的更新代码。
Following is the updated code of Application to use above classes.
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);
}
}
Run/Debug Configuration
在eclipse中创建以下 maven configuration 来运行带目标 spring-boot:run 的springboot应用程序。此配置将有助于运行REST API,我们可以使用POSTMAN对其进行测试。
Create following maven configuration in eclipse to run the springboot application with goal spring-boot:run. This configuration will help to run the REST APIs and we can test them using POSTMAN.
Run the application
在 Eclipse 中,运行 Employee Application 配置。Eclipse 控制台将显示类似的输出。
In eclipse, run the Employee Application configuration. Eclipse console will show the similar output.
[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 请求以添加记录。
Once server is up and running, Use Postman to make a POST request to add a record first.
在 POSTMAN 中设置以下参数。
Set the following parameters in POSTMAN.
-
HTTP Method - POST
-
BODY - An employee JSON
{
"id": "1",
"age": "35",
"name": "Julie",
"email": "julie@gmail.com"
}
单击发送按钮并检查响应状态是否为 OK。现在执行 GET 请求以获取所有记录。
Click on Send Button and check the response status to be OK. Now make a GET Request to get all records.
在 POSTMAN 中设置以下参数。
Set the following parameters in POSTMAN.
-
HTTP Method - GET
单击发送按钮并验证响应。
Click the send button and verify the response.
[{
"id": "1",
"age": "35",
"name": "Julie",
"email": "julie@gmail.com"
}]
Spring Boot JPA - Unit Test Repository
要测试存储库,我们需要以下注释和类:
To test a Repository, we need the following annotation and classes −
-
@ExtendWith(SpringExtension.class) − Mark the class to run as test case using SpringExtension class.
-
@SpringBootTest(classes = SprintBootH2Application.class) − Configure the Spring Boot application.
-
@Transactional − To mark repository to do CRUD Operation capable.
-
@Autowired private EmployeeRepository employeeRepository − EmployeeRepository object to be tested.
Example
以下是 EmployeeRepositoryTest 的完整代码。
Following is the complete code of 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;
}
}
Spring Boot JPA - Repository methods
现在让我们分析在已创建的存储库接口中可用的方法。
Let’s now analyze the methods available in repository interface which we’ve created.
Repository - EmployeeRepository.java
以下为实现上述实体创建CRUD操作的存储库的默认代码,Employee。
Following is the default code of Repository to implement CRUD operations on above entity, Employee.
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> {
}
现在,此存储库默认包含以下方法。
Now this repository contains following methods by default.
Sr.No |
Method & Description |
1 |
count(): long returns the number of entities available. |
2 |
delete(Employee entity): void deletes an entity. |
3 |
deleteAll():void deletes all the entities. |
4 |
deleteAll(Iterable< extends Employee > entities):void deletes the entities passed as argument. |
5 |
deleteAll(Iterable< extends Integer > ids):void deletes the entities identified using their ids passed as argument. |
6 |
existsById(Integer id):boolean checks if an entity exists using its id. |
7 |
findAll():Iterable< Employee > returns all the entities. |
8 |
findAllByIds(Iterable< Integer > ids):Iterable< Employee > returns all the entities identified using ids passed as argument. |
9 |
findById(Integer id):Optional< Employee > returns an entity identified using id. |
10 |
save(Employee entity): Employee saves an entity and return the updated one. |
11 |
saveAll(Iterable< Employee> entities): Iterable< Employee> saves all entities passed and return the updated entities. |
Spring Boot JPA - Custom methods
我们在 JPA Methods 章节中检查了存储库中默认提供的这些方法。现在我们添加一个方法,并对其进行测试。
We’ve checked the methods available by default in Repository in JPA Methods chapter. Now let’s add a method and test it.
Repository - EmployeeRepository.java
Example
添加一个通过名字找到员工的方法。
Add a method to find an employee by its name.
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 会根据我们遵循基于属性的命名方式自动创建一个以上方法的实现。让我们在 test 文件中添加测试用例,从而测试所添加的方法。以下文件中的最后两个方法测试了所添加的自定义方法。
Now Spring JPA will create the implementation of above methods automatically as we’ve following the property based nomenclature. Let’s test the methods added by adding their test cases in test file. Last two methods of below file tests the custom methods added.
以下是 EmployeeRepositoryTest 的完整代码。
Following is the complete code of 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);
}
}
Spring Boot JPA - Named Queries
有时会出现需要自定义查询来完成某个测试用例的情况。我们可以使用 @NamedQuery 注解指定实体类中的命名查询,然后再在存储库中声明该方法。以下是示例。
Some time case arises, where we need a custom query to fulfil one test case. We can use @NamedQuery annotation to specify a named query within an entity class and then declare that method in repository. Following is an example.
我们在 JPA Custom Methods 章节中存储库中添加了自定义方法。现在,我们使用 @NamedQuery 添加另一个方法,并对其进行测试。
We’ve added custom methods in Repository in JPA Custom Methods chapter. Now let’s add another method using @NamedQuery and test it.
Entity - Entity.java
以下为Employee的默认代码。它表示一个带id,name,age和email列的Employee表。
Following is the default code of Employee. It represents a Employee table with id, name, age and email columns.
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;
}
}
Repository - EmployeeRepository.java
添加一个通过名字和年龄找到员工的方法。
Add a method to find an employee by its name and age.
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 将使用命名查询中提供的查询,自动创建以上方法的实现。让我们在 test 文件中添加测试用例,从而测试所添加的方法。以下文件中的最后两个方法测试了所添加的命名查询方法。
Now Spring JPA will create the implementation of above methods automatically using the query provided in named query. Let’s test the methods added by adding their test cases in test file. Last two methods of below file tests the named query method added.
以下是 EmployeeRepositoryTest 的完整代码。
Following is the complete code of 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);
}
}
Spring Boot JPA - Custom Query
有时会出现需要自定义查询来完成某个测试用例的情况。我们可以使用 @Query 注解在存储库内指定一个查询。以下是示例。在此示例中,我们使用 Java 持久化查询语言 (JPQL)。
Some time case arises, where we need a custom query to fulfil one test case. We can use @Query annotation to specify a query within a repository. Following is an example. In this example, we are using JPQL, Java Persistence Query Language.
我们在 JPA Named Query 章节中存储库中添加了名为查询的自定义方法。现在,我们使用 @Query 添加另一个方法,并对其进行测试。
We’ve added name query custom methods in Repository in JPA Named Query chapter. Now let’s add another method using @Query and test it.
Repository - EmployeeRepository.java
添加一个按名字对员工列表进行排序的方法。
Add a method to get list of employees order by their names.
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();
}
让我们在 test 文件中添加测试用例,从而测试所添加的方法。以下文件中的最后两个方法测试了所添加的自定义查询方法。
Let’s test the methods added by adding their test cases in test file. Last two methods of below file tests the custom query method added.
以下是 EmployeeRepositoryTest 的完整代码。
Following is the complete code of 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());
}
}
Spring Boot JPA - Native Query
有时会出现需要自定义本机查询来完成某个测试用例的情况。我们可以使用 @Query 注解在存储库内指定一个查询。以下是示例。在此示例中,我们使用本机查询,并在 Query 注解中设置 nativeQuery=true 属性,将查询标记为本机查询。
Some time case arises, where we need a custom native query to fulfil one test case. We can use @Query annotation to specify a query within a repository. Following is an example. In this example, we are using native query, and set an attribute nativeQuery=true in Query annotation to mark the query as native.
我们在 JPA Custom Query 章节中存储库中添加了自定义方法。现在,我们使用本机查询添加另一个方法,并对其进行测试。
We’ve added custom methods in Repository in JPA Custom Query chapter. Now let’s add another method using native query and test it.
Repository - EmployeeRepository.java
添加一个按名字对员工列表进行排序的方法。
Add a method to get list of employees order by their names.
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();
}
让我们在 test 文件中添加测试用例,从而测试所添加的方法。以下文件中的最后两个方法测试了所添加的自定义查询方法。
Let’s test the methods added by adding their test cases in test file. Last two methods of below file tests the custom query method added.
Example
以下是 EmployeeRepositoryTest 的完整代码。
Following is the complete code of 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());
}
}