Spring Data JPA教程

在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:–作为该项目的一部分,提供了以下接口:

Spring Data JPA:–该项目提供以下接口:

存储库层次结构如下所示:

Spring数据存储库层次结构

让我们尝试通过一个示例程序来了解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.项目结构

我们的项目结构如下图所示。

Spring Data JPA教程的项目结构

上面的项目结构使用的是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

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <groupId>com.springjpa</groupId>
  6. <artifactId>SpringJPA-PostgreSQL</artifactId>
  7. <version>0.0.1</version>
  8. <packaging>jar</packaging>
  9. <name>SpringJPA-PostgreSQL</name>
  10. <description>Demo project for Spring Boot JPA - PostgreSQL</description>
  11. <parent>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-parent</artifactId>
  14. <version>2.0.1.RELEASE</version>
  15. <relativePath/>
  16. </parent>
  17. <properties>
  18. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  19. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  20. <java.version>1.9</java.version>
  21. </properties>
  22. <dependencies>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-data-jpa</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-starter-web</artifactId>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.postgresql</groupId>
  33. <artifactId>postgresql</artifactId>
  34. <scope>runtime</scope>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-test</artifactId>
  39. <scope>test</scope>
  40. </dependency>
  41. <dependency>
  42. <groupId>javax.xml.bind</groupId>
  43. <artifactId>jaxb-api</artifactId>
  44. <version>2.3.0</version>
  45. </dependency>
  46. </dependencies>
  47. <build>
  48. <plugins>
  49. <plugin>
  50. <groupId>org.springframework.boot</groupId>
  51. <artifactId>spring-boot-maven-plugin</artifactId>
  52. </plugin>
  53. </plugins>
  54. </build>
  55. </project>

pom.xml文件将包含程序需要的依赖项。

4.2应用类别

对我们来说,Application.java类是SpringJpaPostgreSqlApplication.java类。 该类如下所示。

Spring Boot的SpringJpaPostgreSqlApplication.java类

  1. package com.tutorial;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.boot.CommandLineRunner;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import com.tutorial.repo.EmployeeRepository;
  7. @SpringBootApplication
  8. public class SpringJpaPostgreSqlApplication implements CommandLineRunner{
  9. @Autowired
  10. EmployeeRepository repository;
  11. public static void main(String[] args){
  12. SpringApplication.run(SpringJpaPostgreSqlApplication.class, args);
  13. }
  14. public void run(String... args) throws Exception {
  15. // TODO Auto-generated method stub
  16. }
  17. }

CommandLineRunner接口用于指示当bean包含在Spring Application中时应运行。

4.3模型类别

我们将创建一个Employee.java类作为模型类。 该类如下所示。

程序的模型类

  1. package com.tutorial.model;
  2. import java.io.Serializable;
  3. import javax.persistence.Column;
  4. import javax.persistence.Entity;
  5. import javax.persistence.GeneratedValue;
  6. import javax.persistence.GenerationType;
  7. import javax.persistence.Id;
  8. import javax.persistence.Table;
  9. @Entity
  10. @Table(name = "employee")
  11. public class Employee implements Serializable {
  12. private static final long serialVersionUID = -3009157732242241606L;
  13. @Id
  14. @GeneratedValue(strategy = GenerationType.AUTO)
  15. @Column(name="id")
  16. private long id;
  17. @Column(name = "firstname")
  18. private String firstName;
  19. @Column(name = "lastname")
  20. private String lastName;
  21. @Column(name = "age")
  22. private int age;
  23. protected Employee() {
  24. }
  25. public Employee(String firstName, String lastName,int age) {
  26. this.firstName = firstName;
  27. this.lastName = lastName;
  28. this.age = age;
  29. }
  30. @Override
  31. public String toString() {
  32. return String.format("Employee[id=%d, firstName='%s', lastName='%s', age='%d']", id, firstName, lastName,age);
  33. }
  34. public long getId() {
  35. return id;
  36. }
  37. public void setId(long id) {
  38. this.id = id;
  39. }
  40. public String getFirstName() {
  41. return firstName;
  42. }
  43. public void setFirstName(String firstName) {
  44. this.firstName = firstName;
  45. }
  46. public String getLastName() {
  47. return lastName;
  48. }
  49. public void setLast_Name(String lastName) {
  50. this.lastName = lastName;
  51. }
  52. public int getAge() {
  53. return age;
  54. }
  55. public void setAge(int age) {
  56. this.age = age;
  57. }
  58. }

@Entity :用于定义该类为Entity类。
@Table :此批注用于指定数据库中定义的表名。
@Id :Id注释用于指定Id属性 @GeneratedValue :当我们要设置自动生成的值时使用。 GenerationType是用于生成特定列的值的机制。 @Column :此批注用于将表中的列与类中的属性进行映射。

4.4储存库接口

存储库接口用于扩展CRUD接口。 该接口在程序中添加了存储库层。 Spring Data JPA提供了两种创建查询的主要方法。 然后,在存储库界面中使用这些查询来从数据库中获取数据。

用于扩展CRUD存储库的存储库类

  1. package com.tutorial.repo;
  2. import java.util.List;
  3. import org.springframework.data.jpa.repository.Query;
  4. import org.springframework.data.repository.CrudRepository;
  5. import org.springframework.data.repository.query.Param;
  6. import org.springframework.stereotype.Repository;
  7. import com.tutorial.model.Employee;
  8. @Repository
  9. public interface EmployeeRepository extends CrudRepository<Employee, Long>{
  10. List findByLastName(String lastName);
  11. @Query("SELECT e FROM Employee e WHERE e.age = :age")
  12. public List findByAge(@Param("age") int age);
  13. }

CrudRepositoryCrudRepository Common项目的接口。 上面提到的两种用于查询创建的方法在代码的以下位置使用。

自动自定义查询:

List findByLastName(String lastName);

方法findByLastName包含姓氏作为参数,将用于数据搜索。 另外,将使用JPA查询构建器自动创建查询。

手动自定义查询:

  1. @Query("SELECT e FROM Employee e WHERE e.age = :age")
  2. public List findByAge(@Param("age") int age);

在此方法中,我们手动定义了一个查询以根据年龄取数据,然后将查询与findByAge方法绑定。

4.5属性文件

作为用于连接数据库的Spring Boot的一部分,我们将在属性文件中提供详细信息。 属性文件如下所示。

Spring启动的application.properties文件

  1. spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
  2. spring.datasource.username=postgres
  3. spring.datasource.password=password
  4. spring.jpa.generate-ddl=true
  5. spring.jpa.show-sql=true
  6. spring.jpa.properties.hibernate.format_sql=true

作为属性文件的一部分,提供了数据库URL和凭据。 属性spring.jpa.show-sql=true显示JPA进行数据操作期间生成的SQL查询。

4.6控制器等级

控制器是整个程序中最重要的一类。 这是负责所有url映射的类。 我们在此类本身中添加了用于数据操作的存储库方法。

程序的控制器类

  1. package com.tutorial.controller;
  2. import java.util.List;
  3. import java.util.Optional;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.web.bind.annotation.RequestBody;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import org.springframework.web.bind.annotation.RequestParam;
  10. import org.springframework.web.bind.annotation.RestController;
  11. import com.tutorial.model.Employee;
  12. import com.tutorial.repo.EmployeeRepository;
  13. @RestController
  14. @RequestMapping("/employee")
  15. public class WebController {
  16. @Autowired
  17. EmployeeRepository repository;
  18. @RequestMapping(value="/save",method = RequestMethod.POST)
  19. public HttpStatus insertEmployee(@RequestBody Employee employee){
  20. boolean status = repository.save(employee) != null;
  21. return status? HttpStatus.CREATED : HttpStatus.BAD_REQUEST;
  22. }
  23. @RequestMapping("/findall")
  24. public List findAll(){
  25. return (List) repository.findAll();
  26. }
  27. @RequestMapping("/findbyid")
  28. public Optional findById(@RequestParam("id") long id){
  29. Optional result = repository.findById(id);
  30. return result;
  31. }
  32. @RequestMapping("/findbylastname")
  33. public List fetchDataByLastName(@RequestParam("lastname") String lastName){
  34. return repository.findByLastName(lastName);
  35. }
  36. @RequestMapping("/findbyage")
  37. public List fetchDataByAge(@RequestParam("age") int age){
  38. return repository.findByAge(age);
  39. }
  40. }

@RestController标记用于将类定义为rest控制器类。
@RequestMapping标记指定请求的路径映射。 值属性指定URL映射,方法属性指定它的方法类型,例如GET,POST,PUT等。 如果默认情况下不指定method属性,则该方法被视为GET方法。

在此类中,我们自动连接了存储库,并使用界面中可用的方法进行数据检索,插入和删除。

为了运行spring boot应用程序,我们必须提供命令spring-boot: run

5.输出

下面提到的查询可用于在PostgreSQL中创建Employee表。

用于查询Employee表的SQL查询

  1. create table employee (
  2. id serial not null primary key,
  3. firstName varchar(20) not null,
  4. lastName varchar(20) not null,
  5. age integer not null
  6. );

让我们检查数据库中可用的数据。 数据库中的当前可用数据如下所示。

PostgreSQL中的数据

现在,让我们尝试使用postman集合来查找findall API,以获取结果行。 结果将如下所示在邮递员上。

Findall API在邮递员上的结果

为了在数据库中添加一些雇员对象。 我们将使用save API并将传递一个employee对象。

使用保存API将对象存储在DB中

让我们检查数据库中保存API的用法。 该数据库将如下所示。

使用Save API保存数据后

同样,我们可以使用findbylastname API来查找具有request参数中提供的姓氏的记录。

findbylastname API的结果

让我们看看绑定到手动自定义查询的方法的结果。

findByAge API的结果

6.总结

本教程的摘要在下面提到。

  1. SpringData JPA提供了用于JPA持久性API的存储库抽象。
  2. 我们了解了CRUD存储库的用法。
  3. 我们使用自动自定义查询来基于姓氏搜索行。
  4. 我们了解了手动定制查询的创建。
  5. JPA异常翻译取决于@Repository标记。

7.下载Eclipse项目

这是使用SpringBoot的SpringData JPA教程。

您可以在此处下载此示例的完整源代码: SpringJPA-PostgreSQL.zip

翻译自: https://www.javacodegeeks.com/2018/05/spring-data-jpa-tutorial.html



原文转载:https://blog.csdn.net/dnc8371/article/details/106701798


posted @ 2022-06-16 01:07  独苏  阅读(989)  评论(0编辑  收藏  举报