Spring Boot的Spring Data JPA示例

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必须下载所有必需的插件和工件才能完成生成任务。

使用Maven的JPA项目设置

请注意,现在,您将在所选目录中拥有一个与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操作以及分页概念。

当我们引入基于pageSizepageNumber从数据库中获取所有对象时,使用分页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应用程序的主类中使用CommandLineRunnerCommandLineRunner在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

一旦运行项目,我们将看到以下输出:

数据JPA项目输出

如预期的那样,我们首先创建了一些样本数据,并通过调用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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值