Học viên: Lê Đăng Quang
Lớp: Java Fullstack 15
Email: ledangquang443@gmail.com
Số điện thoại: 0929554386
Nguồn tham khảo: https://www.baeldung.com/spring-data-jpa-stored-procedures


1. Tổng quan

Một stored procedure là một nhóm các câu lệnh SQL được định nghĩa sẵn trong cơ sở dữ liệu. Trong Java, có nhiều cách để truy cập stored procedure. Trong bài hướng dẫn này, chúng ta sẽ tìm hiểu cách gọi stored procedure từ Spring Data JPA Repositories.

2. Thiết lập dự án

Chúng ta sẽ sử dụng Spring Boot Starter Data JPA module như lớp truy cập dữ liệu. Chúng ta cũng sử dụng MySQL là cơ sở dữ liệu backend. Do đó, chúng ta cần phải có Spring Data JPA, Spring Data JDBC và MySQL Connector dependencies trong tệp pom.xml của dự án:

<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>

Sau khi chúng ta định nghĩa MySQL dependency, chúng ta có thể cấu hình kết nối cơ sở dữ liệu trong files application.properties như sau:

spring.datasource.url=jdbc:mysql://localhost:3306/demoStoreProcedures?createDatabaseIfNotExist=true
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

3. Khởi tạo lớp Entity

Trong Spring Data JPA, một entity đại diện cho một bảng được lưu trữ trong cơ sở dữ liệu. Do đó, chúng ta có thể tạo một lớp entity để ánh xạ bảng cơ sở dữ liệu, trong ví dụ này sẽ là class Car đại diện cho bảng Car trong cơ sở dữ liệu :

@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. Khởi tạo Stored Procedure

Một stored procedure có thể có tham số đầu vào để chúng ta có thể có được các kết quả khác nhau dựa trên đầu vào đó. Ví dụ, chúng ta có thể tạo một stored procedure nhận một tham số đầu vào của kiểu integer và trả về một danh sách các xe có year thỏa mãn điều kiện sau:

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

Một stored procedure cũng có thể sử dụng các tham số đầu ra để trả về dữ liệu cho các ứng dụng. Ví dụ, chúng ta có thể tạo một stored procedure nhận một tham số đầu vào của kiểu string và lưu trữ kết quả truy vấn vào một tham số đầu ra:

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. Tham chiếu tới các stored procedure trong repository:

Trong Spring Data JPA, các repository là nơi chúng ta cung cấp các hoạt động với cơ sở dữ liệu. Chúng ta có thể xây dựng một repository cho các hoạt động với cơ sở dữ liệu trên đối tượng Car, và tham chiếu đến các stored procedure trong repository này:

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

Tiếp theo, hãy thêm một vài phương thức vào repository của chúng ta để gọi tới stored procedure:

5.1 Gọi trực tiếp qua tên stored procedure

Chúng ta có thể định nghĩa một stored procedure bằng cách sử dụng annotation “@Procedure” và map trực tiếp tới stored procedure qua tên.

Có 4 cách để thực hiện điều này:
Cách 1:

@Procedure
int GET_TOTAL_CARS_BY_MODEL(String model);

Cách 2:

Nếu bạn muốn định nghĩa một cái tên khác cho phương thức của bạn, chúng ta có thể để tên của stored procedure như một phần tử của annotation “@Procedure”.

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

Cách 3:

Sử dụng thuộc tính “procedureName

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

Cách 4:

Sử dụng thuộc tính “value”

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

5.2 Định nghĩa stored procedure trong Entity

@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
}

Sau đó chúng ta có thể định nghĩa trong repository như sau:

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

Chúng ta sử dụng thuộc tính “name” để liên kết tới stored procedure được định nghĩa trong entity. Để khai báo phương thức của repository, chúng ta sử dụng @Param để kết nối với tham số đầu vào của stored procedure. Chúng ta cũng sẽ phải kết nối giá trị đầu ra của stored procedure với giá trị trả về của phương thức repository.

5.3 Liên kết stored procedure bằng Annotation @Query

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

6. Tổng kết

Trong bài viết này, chúng ta đã tìm hiểu cách truy cập các tstored procedure thông qua các repository JPA. Chúng ta cũng đã thảo luận về ba cách đơn giản để tham chiếu đến các stored procedure trong các repository JPA.