在Java类或对象与关系数据库之间管理数据是一项非常繁琐且棘手的任务。 DAO层通常包含许多样板代码,应简化这些样板代码,以减少代码行数并使代码可重复使用。
在本教程中,我们将讨论Spring数据的JPA实现。
1.简介
1.1什么是JPA?
JPA或Java Persistence API是Java规范,用于访问,管理和持久化Java类或对象与关系数据库之间的数据。 该规范是EJB 3.0的一部分。
JPA不是实现或产品,它只是一个规范。 它包含需要实现的一组接口。 它是一个框架,为JPA实现提供了额外的抽象层。 存储库层将包含三层,如下所述。
- Spring Data JPA:–提供Spring数据存储库接口,这些接口可用于创建JPA存储库。
- Spring Data Commons:–它提供了在特定于数据存储的spring数据项目之间共享的基础结构。
- 实现JPA持久性API的JPA提供程序。
Spring数据JPA允许我们不添加任何存储库层来编写任何样板代码。
1.2 JPA的历史
JPA2.0:– JPA2.0的开发始于2007年,名称为JSR317。该版本被标记为2.0,因为无法获得1.0的共识。 重点是解决著名供应商ORM所提供的功能。
JPA 2.1: -JPA2.1于2011年7月作为JSR 338开始。一些主要功能是实体图,存储过程,转换器等。
JPA 2.2: -JPA2.2是2017年JPA系列的最新功能。它包括对Java 8日期和时间类型的支持以及流查询结果的功能。
JPA仍在进行大量更改,我们可以期待不久的JPA的更新版本。
1.3 Spring数据仓库
Spring Data Commons项目提供了存储库抽象,该存储库抽象由特定于数据存储的子项目扩展。
我们必须熟悉Spring Data仓库接口,因为它将帮助我们实现接口。 让我们看一下接口。
Spring Data Commons:–作为该项目的一部分,提供了以下接口:
-
Repository<T, ID extends Serializable>
:此接口是标记接口。- 它捕获托管实体的类型和实体ID的类型。
- 扫描类路径时,它可以帮助Spring容器发现“具体的”存储库接口。
-
CrudRepository<T, ID extends Serializable>
:它为受管实体提供CRUD操作。 -
PagingAndSortingRepository<T, ID extends Serializable>
:此接口声明用于对从数据库中检索到的实体进行排序和分页的方法。 -
QueryDslPredicateExecutor<T>
:它不是“存储库接口”。 它声明使用QueryDsl
谓词对象从数据库检索实体的方法。
Spring Data JPA:–该项目提供以下接口:
-
JpaRepository<T, ID extends Serializable>
:此接口是JPA特定的存储库接口,它将公共存储库接口声明的方法组合在单个接口后面。 -
JpaSpecificationExecutor<T>
:再次不是“存储库接口”。 它声明使用通过使用JPA标准API的Specification<T>
对象从数据库检索实体的方法。
存储库层次结构如下所示:
让我们尝试通过一个示例程序来了解Spring Data JPA。
1.4 Spring数据自定义查询
让我们考虑一个用例,其中我们必须基于查询从数据库中获取数据。 编写自定义查询是非常有用的情况。 Spring Data JPA具有不同的编写自定义查询的方式。 我们将大致分类如下所述的方式。
自动自定义查询:自动自定义查询的创建也称为从方法名称查询创建。 Spring Data JPA具有用于查询创建的内置机制,可用于直接从查询方法的方法名称解析查询。 该机制首先从方法名称中删除公共前缀,并从其余方法名称中解析查询的约束。 为了使用这种方法,我们必须确保通过合并实体对象的属性名称和支持的关键字来创建存储库接口的方法名称。
使用这种方法的优点是它很容易实现。 但是限制是,如果查询包含多个参数,则方法名将不可读。 同样,JPA不支持的关键字(例如lower)也不适用于此方法。
手动自定义查询:手动自定义查询也称为使用@Query
标记创建查询。 @Query
批注将用于使用JPA查询语言创建查询,并将这些查询直接绑定到存储库接口的方法。 调用查询方法时,Spring Data JPA将执行@Query
注释指定的查询。
这种方法的优点是您可以使用JPA查询语言来创建查询。 此外,查询仍位于存储库层。 这种方法的局限性是@Query
只能在支持JPA查询语言时使用。
下面提到的程序使用这两种方法。
1.5 Spring Data JPA异常转换
需要考虑的重点是因为默认的Spring ORM模板未与SPring JPA一起使用,是否通过使用Spring Data JPA丢失了异常转换?是否不将JPA异常转换为Spring的DataAccessException层次结构?
答案是否定的 。 通过在DAO上使用@Repository
批注,仍可以启用异常转换。 注释使Spring Bean后处理器可以为所有@Repository
Bean提供在Container中找到的所有PersistenceExceptionTranslator
实例的建议,并像以前一样提供异常转换。
2.工具与技术
让我们看看用于构建程序的技术和工具。
- Eclipse Oxygen.2发布(4.7.2)
- Java –版本9.0.4
- Maven – 3.5.3
- Spring启动– 2.0.1-发布
- PostgreSQL – 10
- 邮差
3.项目结构
我们的项目结构如下图所示。
上面的项目结构使用的是Maven。 也可以使用Gradle创建该项目,并且pom.xml将替换为build.gradle文件。 该项目的结构将稍微延迟使用Gradle进行构建。
4.方案目标
作为程序的一部分,我们将尝试使用spring boot创建一个简单的Web服务。 该Web服务将用于PostgreSQL数据库上的数据操作。
4.1 pom.xml
该程序的pom.xml
文件如下所示。
使用Spring Boot的SpringData JPA的pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.springjpa</groupId><artifactId>SpringJPA-PostgreSQL</artifactId><version>0.0.1</version><packaging>jar</packaging><name>SpringJPA-PostgreSQL</name><description>Demo project for Spring Boot JPA - PostgreSQL</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version><relativePath/> </parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.9</java.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>org.postgresql</groupId><artifactId>postgresql</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.0</version>
</dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
pom.xml文件将包含程序需要的依赖项。
4.2应用类别
对我们来说,Application.java类是SpringJpaPostgreSqlApplication.java
类。 该类如下所示。
Spring Boot的SpringJpaPostgreSqlApplication.java类
package com.tutorial;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;import com.tutorial.repo.EmployeeRepository;@SpringBootApplication
public class SpringJpaPostgreSqlApplication implements CommandLineRunner{@AutowiredEmployeeRepository repository;public static void main(String[] args){SpringApplication.run(SpringJpaPostgreSqlApplication.class, args);}public void run(String... args) throws Exception {// TODO Auto-generated method stub}}
CommandLineRunner
接口用于指示当bean包含在Spring Application中时应运行。
4.3模型类别
我们将创建一个Employee.java
类作为模型类。 该类如下所示。
程序的模型类
package com.tutorial.model;import java.io.Serializable;import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;@Entity
@Table(name = "employee")
public class Employee implements Serializable {private static final long serialVersionUID = -3009157732242241606L;@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name="id")private long id;@Column(name = "firstname")private String firstName;@Column(name = "lastname")private String lastName;@Column(name = "age")private int age;protected Employee() {}public Employee(String firstName, String lastName,int age) {this.firstName = firstName;this.lastName = lastName;this.age = age;}@Overridepublic String toString() {return String.format("Employee[id=%d, firstName='%s', lastName='%s', age='%d']", id, firstName, lastName,age);}public long getId() {return id;}public void setId(long id) {this.id = id;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLast_Name(String lastName) {this.lastName = lastName;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
@Entity
:用于定义该类为Entity类。
@Table
:此批注用于指定数据库中定义的表名。
@Id
:Id注释用于指定Id属性 @GeneratedValue
:当我们要设置自动生成的值时使用。 GenerationType
是用于生成特定列的值的机制。 @Column
:此批注用于将表中的列与类中的属性进行映射。
4.4储存库接口
存储库接口用于扩展CRUD接口。 该接口在程序中添加了存储库层。 Spring Data JPA提供了两种创建查询的主要方法。 然后,在存储库界面中使用这些查询来从数据库中获取数据。
用于扩展CRUD存储库的存储库类
package com.tutorial.repo;import java.util.List;import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;import com.tutorial.model.Employee;@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Long>{List findByLastName(String lastName);@Query("SELECT e FROM Employee e WHERE e.age = :age")public List findByAge(@Param("age") int age);
}
CrudRepository
是CrudRepository
Common项目的接口。 上面提到的两种用于查询创建的方法在代码的以下位置使用。
自动自定义查询:
List findByLastName(String lastName);
方法findByLastName
包含姓氏作为参数,将用于数据搜索。 另外,将使用JPA查询构建器自动创建查询。
手动自定义查询:
@Query("SELECT e FROM Employee e WHERE e.age = :age")public List findByAge(@Param("age") int age);
在此方法中,我们手动定义了一个查询以根据年龄取数据,然后将查询与findByAge
方法绑定。
4.5属性文件
作为用于连接数据库的Spring Boot的一部分,我们将在属性文件中提供详细信息。 属性文件如下所示。
Spring启动的application.properties文件
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
作为属性文件的一部分,提供了数据库URL和凭据。 属性spring.jpa.show-sql=true
显示JPA进行数据操作期间生成的SQL查询。
4.6控制器等级
控制器是整个程序中最重要的一类。 这是负责所有url映射的类。 我们在此类本身中添加了用于数据操作的存储库方法。
程序的控制器类
package com.tutorial.controller;import java.util.List;
import java.util.Optional;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import com.tutorial.model.Employee;
import com.tutorial.repo.EmployeeRepository;@RestController
@RequestMapping("/employee")
public class WebController {@AutowiredEmployeeRepository repository;@RequestMapping(value="/save",method = RequestMethod.POST)public HttpStatus insertEmployee(@RequestBody Employee employee){boolean status = repository.save(employee) != null; return status? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;}@RequestMapping("/findall")public List findAll(){return (List) repository.findAll();}@RequestMapping("/findbyid")public Optional findById(@RequestParam("id") long id){Optional result = repository.findById(id);return result;}@RequestMapping("/findbylastname")public List fetchDataByLastName(@RequestParam("lastname") String lastName){return repository.findByLastName(lastName);}@RequestMapping("/findbyage")public List fetchDataByAge(@RequestParam("age") int age){return repository.findByAge(age);}
}
@RestController
标记用于将类定义为rest控制器类。
@RequestMapping
标记指定请求的路径映射。 值属性指定URL映射,方法属性指定它的方法类型,例如GET,POST,PUT等。
如果默认情况下不指定method属性,则该方法被视为GET方法。
在此类中,我们已自动连接存储库,并使用界面中可用的方法进行数据检索,插入和删除。
为了运行spring boot应用程序,我们必须提供命令spring-boot: run
。
5.输出
下面提到的查询可用于在PostgreSQL中创建Employee表。
用于查询Employee表的SQL查询
create table employee (
id serial not null primary key,
firstName varchar(20) not null,
lastName varchar(20) not null,
age integer not null
);
让我们检查数据库中可用的数据。 数据库中的当前可用数据如下所示。
现在,让我们尝试使用postman集合来查找findall API,以获取结果行。 结果将如下所示在邮递员上。
为了在数据库中添加一些雇员对象。 我们将使用save API并将传递一个employee对象。
让我们检查数据库中保存API的用法。 该数据库将如下所示。
同样,我们可以使用findbylastname
API来查找具有request参数中提供的姓氏的记录。
让我们看看绑定到手动自定义查询的方法的结果。
6.总结
本教程的摘要在下面提到。
- SpringData JPA提供了用于JPA持久性API的存储库抽象。
- 我们了解了CRUD存储库的用法。
- 我们使用自动自定义查询来基于姓氏搜索行。
- 我们了解了手动定制查询的创建。
- JPA异常翻译取决于
@Repository
标记。
7.下载Eclipse项目
这是使用SpringBoot的SpringData JPA教程。
翻译自: https://www.javacodegeeks.com/2018/05/spring-data-jpa-tutorial.html