1.简介
在本文中,我们将演示如何利用功能强大的Spring Data JPA API与本课程中的数据库(内存中的H2数据库)进行交互。
Spring Data JPA提供了一组非常强大且高度抽象的接口,用于与任何基础数据库进行交互。 数据库可以是MySQL,MongoDB,Elasticsearch或任何其他受支持的数据库。 Spring Data JPA的其他优点包括:
- 支持根据JPA公约建立扩展存储库
- 内置分页支持和动态查询执行
- 支持基于XML的实体映射
在此示例中,我们将使用H2内存数据库。 数据库的选择不应影响我们将构建的Spring Data定义,因为这是Spring Data JPA提供的主要优点。 它使我们能够将数据库查询与应用程序逻辑完全分开。
2.项目设置
我们将使用许多Maven原型之一为我们的示例创建一个示例项目。 要创建项目,请在将用作工作空间的目录中执行以下命令:
mvn archetype:generate -DgroupId=com.javacodegeeks.example -DartifactId=JCG-SpringDataJPA-example -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
如果您是第一次运行maven,则完成生成命令将花费几秒钟,因为maven必须下载所有必需的插件和工件才能完成生成任务。
请注意,现在,您将在所选目录中拥有一个与artifactId
同名的新目录。 现在,随时在您喜欢的IDE中打开项目。
最后,我们使用一个简单的maven命令来代替使用IDE来创建该项目。 这有助于我们使项目设置和初始化不受您可能使用的任何特定IDE的影响。
3. Maven依赖
首先,我们需要在项目中添加适当的Maven依赖项。 我们将以下依赖项添加到我们的pom.xml文件中:
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</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>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
在此处找到与Spring相关的最新依赖项。
请注意,我们还在此处添加了H2数据库依赖关系及其范围(作为运行时),因为一旦应用程序停止运行,H2数据就会被冲走。 在本课程中,我们将不会关注H2的实际工作原理,而是将自己局限于Spring Data JPA API。 您可能还会看到我们如何使用Spring应用程序配置嵌入式H2控制台 。
4.项目结构
在继续进行并开始处理该项目的代码之前,让我们在此介绍一下将所有代码添加到项目后将拥有的projet结构:
我们将项目分为多个包,以便遵循关注点分离的原则,并且代码保持模块化。
5.定义模型
我们将在我们的项目中添加一个非常简单的模型Person
。 它的定义将非常标准,例如:
人.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//standard getters and setters
@Override
public String toString() {
return String.format("Person{id=%d, name='%s', age=%d}", id, name, age);
}
}
为了简洁起见,我们省略了标准的getter和setter方法,但是由于Jackson在对象的序列化和反序列化过程中使用它们,因此必须将它们制成。
@Entity
注释将该POJO标记为对象,该对象将由Spring Data API管理,并且其字段将被视为表列(除非标记为transient )。
最后,我们为toString()
方法添加了一个自定义实现,以便在测试应用程序时可以打印相关数据。
6.定义JPA存储库
JPA为我们提供了一种非常简单的定义JPA存储库接口的方法。
在了解如何定义JPA信息库之前,我们需要记住,只有在利用与JPA相关的功能时,才使每个JPA接口与数据库表的单个实体进行交互。 如果我们看一下接口定义,我们将对此有深刻的理解:
PersonRepository.java
import com.javacodegeeks.jpaexample.model.Person;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
}
尽管上面的接口定义是空的,但我们仍然需要了解一些要点:
-
@Repository
批注将此接口标记为Spring Bean,该Bean在应用程序启动时初始化。 借助此注释,Spring可以管理异常数据库交互引发的正常运行 - 我们使用
Person
作为参数来表示此JPA接口将管理Person
实体 - 最后,我们还传递了数据类型
Long
作为参数。 这表示Person
实体包含唯一标识符,其类型为Long
7.制作服务界面
在本节中,我们将定义一个服务接口,该接口将充当实现的合同,并重新表达我们的服务必须支持的所有操作。 这些动作将与结交新用户以及获取与数据库中对象有关的信息有关。
这是我们将使用的合同定义:
PersonService.java
import com.javacodegeeks.jpaexample.model.Person;
import java.util.List;
public interface PersonService {
Person createPerson(Person person);
Person getPerson(Long id);
Person editPerson(Person person);
void deletePerson(Person person);
void deletePerson(Long id);
List getAllPersons(int pageNumber, int pageSize);
List getAllPersons();
long countPersons();
}
我们在该合同中提到了所有四个CRUD操作以及分页概念。
当我们引入基于pageSize
和pageNumber
从数据库中获取所有对象时,使用分页API很重要。 pageSize
属性表示从数据库中获取的对象数,而pageNumber
属性用作查询的跳过部分。 有关Spring分页如何工作的详细课程,请阅读本课程 。
8.提供服务实施
我们将使用上面的接口定义来提供其实现,以便我们可以执行与我们先前定义的Person
实体相关的CRUD操作。 我们将在这里执行:
PersonServiceImpl.java
import com.javacodegeeks.jpaexample.model.Person;
import com.javacodegeeks.jpaexample.repository.PersonRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PersonServiceImpl implements PersonService {
@Autowired
private PersonRepository personRepository;
@Override
public Person createPerson(Person person) {
return personRepository.save(person);
}
@Override
public Person getPerson(Long id) {
return personRepository.findOne(id);
}
@Override
public Person editPerson(Person person) {
return personRepository.save(person);
}
@Override
public void deletePerson(Person person) {
personRepository.delete(person);
}
@Override
public void deletePerson(Long id) {
personRepository.delete(id);
}
@Override
public List<Person> getAllPersons(int pageNumber, int pageSize) {
return personRepository.findAll(new PageRequest(pageNumber, pageSize)).getContent();
}
@Override
public List<Person> getAllPersons() {
return personRepository.findAll();
}
@Override
public long countPersons() {
return personRepository.count();
}
}
令人惊讶的是,所有方法实现都只是一行代码。 这显示了JPA存储库提供给我们的抽象级别。
上面的大多数操作都很容易理解。 需要注意的主要事情是,我们从未在存储库中提供过像getAllPersons()
等那样的任何方法! 那么这些方法是如何一起出现的呢? 答案还是在于JPA存储库提供给我们的抽象。 所有方法(如findAll()
, delete()
, save(...)
等)都内置在我们在存储库接口定义中扩展的JpaRepository
中。
9.使用CommandLineRunner
为了测试我们现在编写的收费代码以及数据库交互部分,我们将在Spring Boot应用程序的主类中使用CommandLineRunner
。 CommandLineRunner
在Spring Boot应用程序的main()
方法被调用之前运行,因此,它是执行任何初始化步骤或测试代码的理想空间。
为了测试应用程序,我们将使用服务bean在我们的类中执行数据库操作:
pom.xml
import com.javacodegeeks.jpaexample.model.Person;
import com.javacodegeeks.jpaexample.service.PersonService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DataJpaApp implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger("JCG");
@Autowired
private PersonService service;
public static void main(String[] args) {
SpringApplication.run(DataJpaApp.class, args);
}
@Override
public void run(String... strings) {
LOG.info("Current objects in DB: {}", service.countPersons());
Person person = service.createPerson(new Person("Shubham", 23));
LOG.info("Person created in DB : {}", person);
LOG.info("Current objects in DB: {}", service.countPersons());
person.setName("Programmer");
Person editedPerson = service.editPerson(person);
LOG.info("Person edited in DB : {}", person);
service.deletePerson(person);
LOG.info("After deletion, count: {}", service.countPersons());
}
}
在上面的示例代码中,我们只是简单地调用了我们在服务中创建的一些重要方法,例如创建了一些数据并在以后的方法调用中对其进行了访问。
现在,我们最终将使用Maven本身运行我们的项目(再次独立于任何IDE来运行我们的项目)。
10.运行应用程序
使用maven可以轻松运行应用程序,只需使用以下命令:
运行应用程序
mvn spring-boot:run
一旦运行项目,我们将看到以下输出:
如预期的那样,我们首先创建了一些样本数据,并通过调用count()
方法调用对其进行了确认。 最后,我们删除了数据,并再次通过count()
方法调用进行了确认。
11.下载源代码
这是Spring Boot和Spring Data JPA API以及内存中H2数据库的示例。
您可以在此处下载此示例的完整源代码: Spring Data JPA示例
翻译自: https://www.javacodegeeks.com/2018/03/spring-data-jpa-example-with-spring-boot.html