ZetCode

Spring Boot JpaRepository

上次修改时间:2023 年 7 月 23 日

SpringBoot JpaRepository 教程展示了如何在 Spring Boot 应用程序中使用 JpaRepository 来管理数据。

Spring 是一个流行的 Java 应用程序框架。Spring Boot 旨在以最小的努力创建独立的、生产级的基于 Spring 的应用程序。

Spring Data

Spring Data 是一个基于 Spring 的数据访问编程模型。 它减少了处理数据库和数据存储所需的代码量。 它由几个模块组成。 Spring Data JPA 简化了使用 JPA 技术的 Spring 应用程序的开发。

使用 Spring Data,我们为应用程序中的每个域实体定义一个存储库接口。 存储库包含用于执行 CRUD 操作、排序和分页数据的方法。 @Repository 是一个标记注解,它指示底层接口是一个存储库。 存储库通过扩展特定的存储库接口来创建,例如 CrudRepositoryPagingAndSortingRepositoryJpaRepository

Spring Data 与 Spring MVC 控制器有高级集成,并提供从存储库方法名称动态派生查询的功能。

JpaRepository

JpaRepositoryRepository 的 JPA 特定扩展。 它包含 CrudRepositoryPagingAndSortingRepository 的完整 API。 因此,它包含用于基本 CRUD 操作以及分页和排序的 API。

Spring Boot JpaRepository 示例

以下 Spring Boot 应用程序使用 JpaRepository 管理 City 实体。 数据保存在 H2 数据库中。 该应用程序是一个控制台程序。

build.gradle
...
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           ├───model
│   │           │       City.java
│   │           └───repository
│   │                   CityRepository.java
│   └───resources
│           application.properties
└───test
    └───java

这是项目结构。

build.gradle
plugins {
    id 'org.springframework.boot' version '3.1.1'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
}

这是 Gradle 构建文件。 spring-boot-starter-data-jpa 是一个用于将 Spring Data JPA 与 Hibernate 一起使用的启动器。

resources/application.properties
spring.main.banner-mode=off
logging.pattern.console=%clr(%d{yy-MM-dd E HH:mm:ss.SSS}){blue} %clr(%-5p) %clr(%logger{0}){blue} %clr(%m){faint}%n

application.properties 是主要的 Spring Boot 配置文件。 使用 spring.main.banner-mode 属性,我们关闭 Spring banner。 logging.pattern.console 定义控制台的日志模式。

com/zetcode/model/City.java
package com.zetcode.model;

import java.util.Objects;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "cities")
public class City {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;
    private int population;

    public City() {
    }

    public City(String name, int population) {

        this.name = name;
        this.population = population;
    }

    public Long getId() {

        return id;
    }

    public void setId(Long id) {

        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {

        this.name = name;
    }

    public int getPopulation() {

        return population;
    }

    public void setPopulation(int population) {

        this.population = population;
    }

    @Override
    public int hashCode() {

        int hash = 7;
        hash = 79 * hash + Objects.hashCode(this.id);
        hash = 79 * hash + Objects.hashCode(this.name);
        hash = 79 * hash + this.population;

        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }

        final City other = (City) obj;
        if (this.population != other.population) {
            return false;
        }

        if (!Objects.equals(this.name, other.name)) {
            return false;
        }

        return Objects.equals(this.id, other.id);
    }

    @Override
    public String toString() {

        var builder = new StringBuilder();
        builder.append("City{id=").append(id).append(", name=")
                .append(name).append(", population=")
                .append(population).append("}");

        return builder.toString();
    }
}

这是 City 实体。 它包含以下属性:idnamepopulation

com/zetcode/repository/CityRepository.java
package com.zetcode.repository;

import com.zetcode.model.City;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CityRepository extends JpaRepository<City, Long> {

}

CityRepository 继承自 JpaRepository。 它提供了实体及其主键的类型。

注意: 在 Java 企业应用程序中,定义一个与存储库一起工作的服务层是一个好习惯。 为了简单起见,我们跳过服务层。

com/zetcode/MyRunner.java
package com.zetcode;

import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);

    private final CityRepository cityRepository;

    @Autowired
    public MyRunner(CityRepository cityRepository) {
        this.cityRepository = cityRepository;
    }

    @Override
    public void run(String... args) throws Exception {

        cityRepository.save(new City("Bratislava", 432000));
        cityRepository.save(new City("Budapest", 1759000));
        cityRepository.save(new City("Prague", 1280000));
        cityRepository.save(new City("Warsaw", 1748000));
        cityRepository.save(new City("Los Angeles", 3971000));
        cityRepository.save(new City("New York", 8550000));
        cityRepository.save(new City("Edinburgh", 464000));

        logger.info("# of cities: {}", cityRepository.count());

        logger.info("All cities unsorted:");
        var cities = cityRepository.findAll();
        logger.info("{}", cities);

        logger.info("------------------------");

        logger.info("All cities sorted by name in descending order");
        var sortedCities = cityRepository.findAll(Sort.by(Sort.Direction.DESC, "name"));
        logger.info("{}", sortedCities);

        logger.info("------------------------");

        logger.info("Deleting all cities");
        cityRepository.deleteAllInBatch();

        logger.info("# of cities: {}", cityRepository.count());
    }
}

MyRunner 中,我们使用 JpaRepository 的各种方法。

private final CityRepository cityRepository;

@Autowired
public MyRunner(CityRepository cityRepository) {
    this.cityRepository = cityRepository;
}

我们将 CityRepository 注入到 cityRepository 字段中。

cityRepository.save(new City("Bratislava", 432000));

使用 save 插入一个新的城市。

logger.info("# of cities: {}", cityRepository.count());

我们使用 count 统计城市的数量。

logger.info("All cities unsorted:");
var cities = cityRepository.findAll();
logger.info("{}", cities);

使用 findAll,我们获取所有城市。

logger.info("All cities sorted by name in descending order");
var sortedCities = cityRepository.findAll(Sort.by(Sort.Direction.DESC, "name"));
logger.info("{}", sortedCities);

通过将 Sort 对象传递给 findAll 方法,我们获取按名称降序排序的所有城市。

logger.info("Deleting all cities");
cityRepository.deleteAllInBatch();

我们使用 deleteAllInBatch 批量删除所有城市。

com/zetcode/Application.java
package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

`Application` 设置了 Spring Boot 应用程序。

...
... INFO  MyRunner # of cities: 7
... INFO  MyRunner All cities unsorted:
... INFO  MyRunner [City{id=1, name=Bratislava, population=432000}, City{id=2, name=Budapest, population=1759000}, City{id=3, name=Prague, population=1280000}, City{id=4, name=Warsaw, population=1748000}, City{id=5, name=Los Angeles, population=3971000}, City{id=6, name=New York, population=8550000}, City{id=7, name=Edinburgh, population=464000}]
... INFO  MyRunner ------------------------
... INFO  MyRunner All cities sorted by name in descending order
... INFO  MyRunner [City{id=4, name=Warsaw, population=1748000}, City{id=3, name=Prague, population=1280000}, City{id=6, name=New York, population=8550000}, City{id=5, name=Los Angeles, population=3971000}, City{id=7, name=Edinburgh, population=464000}, City{id=2, name=Budapest, population=1759000}, City{id=1, name=Bratislava, population=432000}]
... INFO  MyRunner ------------------------
... INFO  MyRunner Deleting all cities
... INFO  MyRunner # of cities: 0
...

在本文中,我们使用 JpaRepository 管理我们的应用程序数据。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出 所有 Spring Boot 教程