«1. Обзор

Хранимая процедура — это группа предопределенных операторов SQL, хранящихся в базе данных. В Java существует несколько способов доступа к хранимым процедурам. В этом руководстве мы покажем, как вызывать хранимые процедуры из репозиториев Spring Data JPA.

2. Настройка проекта

В этом руководстве мы будем использовать модуль JPA Spring Boot Starter Data в качестве уровня доступа к данным. Мы также будем использовать MySQL в качестве нашей серверной базы данных. Поэтому нам понадобятся зависимости Spring Data JPA, Spring Data JDBC и MySQL Connector в файле pom.xml нашего проекта:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

Получив определение зависимости MySQL, мы можем настроить подключение к базе данных в приложении. файл свойств:

spring.datasource.url=jdbc:mysql://localhost:3306/baeldung
spring.datasource.username=baeldung
spring.datasource.password=baeldung

3. Класс сущности

В Spring Data JPA сущность представляет собой таблицу, хранящуюся в базе данных. Таким образом, мы можем создать класс сущности для сопоставления таблицы базы данных car:

@Entity
public class Car {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private long id;

    @Column
    private String model;

    @Column
    private Integer year;

   // standard getters and setters
}

4. Создание хранимой процедуры

Хранимая процедура может иметь параметры, чтобы мы могли получать разные результаты на основе входных данных. Например, мы можем создать хранимую процедуру, которая принимает входной параметр целочисленного типа и возвращает список автомобилей:

CREATE PROCEDURE FIND_CARS_AFTER_YEAR(IN year_in INT)
BEGIN 
    SELECT * FROM car WHERE year >= year_in ORDER BY year;
END

Хранимая процедура также может использовать выходные параметры для возврата данных вызывающим приложениям. Например, мы можем создать хранимую процедуру, которая принимает входной параметр строкового типа и сохраняет результат запроса в выходной параметр:

CREATE PROCEDURE GET_TOTAL_CARS_BY_MODEL(IN model_in VARCHAR(50), OUT count_out INT)
BEGIN
    SELECT COUNT(*) into count_out from car WHERE model = model_in;
END

5. Ссылки на хранимые процедуры в репозитории

В Spring Data JPA репозитории где мы предоставляем операции с базой данных. Следовательно, мы можем создать репозиторий для операций базы данных над сущностью Car и ссылаться на хранимые процедуры в этом репозитории:

@Repository
public interface CarRepository extends JpaRepository<Car, Integer> {
    // ...
}

Далее давайте добавим в наш репозиторий несколько методов, вызывающих хранимые процедуры.

5.1. Прямое сопоставление имени хранимой процедуры

Мы можем определить метод хранимой процедуры с помощью аннотации @Procedure и напрямую сопоставить имя хранимой процедуры.

Есть четыре эквивалентных способа сделать это. Например, мы можем использовать имя хранимой процедуры непосредственно в качестве имени метода:

@Procedure
int GET_TOTAL_CARS_BY_MODEL(String model);

Если мы хотим определить другое имя метода, мы можем поместить имя хранимой процедуры в качестве элемента аннотации @Procedure:

@Procedure("GET_TOTAL_CARS_BY_MODEL")
int getTotalCarsByModel(String model);

Мы также можем использовать атрибут procedureName для сопоставления имени хранимой процедуры:

@Procedure(procedureName = "GET_TOTAL_CARS_BY_MODEL")
int getTotalCarsByModelProcedureName(String model);

Точно так же мы можем использовать атрибут value для сопоставления имени хранимой процедуры:

@Procedure(value = "GET_TOTAL_CARS_BY_MODEL")
int getTotalCarsByModelValue(String model);

5.2. Ссылка на хранимую процедуру, определенную в сущности

Мы также можем использовать аннотацию @NamedStoredProcedureQuery для определения хранимой процедуры в классе сущности:

@Entity
@NamedStoredProcedureQuery(name = "Car.getTotalCardsbyModelEntity", 
  procedureName = "GET_TOTAL_CARS_BY_MODEL", parameters = {
    @StoredProcedureParameter(mode = ParameterMode.IN, name = "model_in", type = String.class),
    @StoredProcedureParameter(mode = ParameterMode.OUT, name = "count_out", type = Integer.class)})
public class Car {
    // class definition
}

Затем мы можем сослаться на это определение в репозитории:

@Procedure(name = "Car.getTotalCardsbyModelEntity")
int getTotalCarsByModelEntiy(@Param("model_in") String model);

~~ ~ Мы используем атрибут name для ссылки на хранимую процедуру, определенную в классе сущности. Для метода репозитория мы используем @Param для соответствия входному параметру хранимой процедуры. Кроме того, мы сопоставляем выходной параметр хранимой процедуры с возвращаемым значением метода репозитория.

5.3. Ссылка на хранимую процедуру с помощью аннотации @Query

Мы также можем вызвать хранимую процедуру напрямую с помощью аннотации @Query:

@Query(value = "CALL FIND_CARS_AFTER_YEAR(:year_in);", nativeQuery = true)
List<Car> findCarsAfterYear(@Param("year_in") Integer year_in);

В этом методе мы используем собственный запрос для вызова хранимой процедуры. Мы сохраняем запрос в атрибуте value аннотации.

Точно так же мы используем @Param для соответствия входному параметру хранимой процедуры. Кроме того, мы сопоставляем выходные данные хранимой процедуры со списком объектов сущности Car.

6. Резюме

В этом руководстве мы показали, как получить доступ к хранимым процедурам через репозитории JPA. Кроме того, мы обсудили два простых способа ссылки на хранимые процедуры в репозиториях JPA.

Как всегда, исходный код статьи доступен на GitHub.