Spring Boot - JPA로 저장 프로시저 사용하기 (StoredProcedureQuery)

반응형

 

이번 포스팅에서는 nativeQuery로 프로시저를 사용하는 것이 아닌,

직접 프로시저 실행하는 명령어를 이용하여 프로시저를 사용합니다.

예제 파일은 깃허브에서 다운로드 가능합니다.

https://github.com/luvris2/spring-boot-jap-stored-procedure-query

 

GitHub - luvris2/spring-boot-jap-stored-procedure-query

Contribute to luvris2/spring-boot-jap-stored-procedure-query development by creating an account on GitHub.

github.com


사용 환경

  • IDE : IntelliJ
  • Java : Open JDK 17
  • Project : Grade
  • DB : SSMS (MS-SQL)
  • DB Management : JPA

프로젝트 설정

설정에 대한 자세한 설명이 필요하다면 아래의 포스팅에서 통해 설정을 진행해주시면 됩니다.

https://luvris2.tistory.com/500

 

Spring Boot - JPA로 쿼리 제어하기(NativeQuery), Entity Manager 설정, persistence.xml 설정, 프로시저 사용하기

예제 파일 https://github.com/luvris2/spring-boot-jap-nativequery GitHub - luvris2/spring-boot-jap-nativequery Contribute to luvris2/spring-boot-jap-nativequery development by creating an account on GitHub. github.com 서론 JPA로 CRUD말고 함수나

luvris2.tistory.com


build.gradle - dependencies

dependencies {
	// MS-SQL
    runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc:9.2.1.jre11'
    // JPA
    implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0'
}

application.yml

# application.yml
spring:
  datasource:
    url: jdbc:sqlserver:// your host name : port ;databaseName= your DB name
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    username: your name
    password: your password

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
    <persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:sqlserver:// 'your host name' : 'port number';databaseName= 'your database name' "/>
            <property name="javax.persistence.jdbc.user" value=" your user name "/>
            <property name="javax.persistence.jdbc.password" value=" your password "/>
        </properties>
    </persistence-unit>
</persistence>

JPA 클래스 설정

EntityManagerFactory를 정의할 클래스

  • 이름은 JpaUtils로 정의, 개인에 맞게 정의
// JpaUtils.java

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class JpaUtils {
    private static final String PERSISTENCE_UNIT_NAME = "myPersistenceUnit"; // replace with your persistence unit name

    private static final EntityManagerFactory emFactory;
    static {
        emFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
    }

    public static EntityManager getEntityManager() {
        return emFactory.createEntityManager();
    }
}

Entity 클래스 정의

  • 조회한 테이블의 데이터타입과 값을 반환 받기 위해 편의상 설정
  • 테이블 애너테이션에 테이블 이름 입력
  • 엔티티 클래스는 없어도 무관
    • 단, 없을 경우 프로시저 처리 결과의 반환 값이 오브젝트 타입이며 형변환 진행해야 함
  • 이름은 ProcedureResultSet 으로 정의, 개인에 맞게 정의
// ProcedureResultSet.java

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
@Table(name="testTable")
public class ProcedureResultSet {
    @Id
    private int id;
    @Column
    private String username;
    @Column
    private String address;
}

 

  • 테이블 확인
select * from testTable;


JPA 저장 프로시저 쿼리 문법

  • createStoredProcedureQuery(프로시저명, 엔티티)
    • 입력한 프로시저 실행
    • 엔티티 클래스를 입력할 경우 해당 컬럼에 설정된 데이터타입으로 값 반환
    • 프로시저명만 입력할 경우 오브젝트 타입으로 값 반환 (형변환 필요)
  • registerStoredProcedureParameter(순서, 데이터타입, 입출력여부)
    • 순서 혹은 파라미터명 : 정수의 숫자로 입력, 혹은 파라미터명을 정의하여 사용
    • 데이터타입 : 데이터 타입 뒤에 .class를 붙임 (예:String.class)
    • 입출력여부 : ParameterMode.IN 혹은 ParameterMode.OUT
  • setParameter(순서, 값)
    • 입력 파라미터에만 해당
    • 순서 혹은 파라미터명 : 정수의 숫자로 입력, 혹은 파라미터명을 정의하여 사용
    • 값 : 설정한 데이터타입에 맞는 형태의 값 입력
  • getOutputParameterValue(순서)
    • 출력 파라미터에만 해당
    • 순서 혹은 파라미터명 : 정수의 숫자 혹은 파라미터명을 입력하여 해당 출력 파라미터의 값 반환

JPA 저장 프로시저 쿼리 클래스 설정

프로시저 내용

  • p_select_all : 해당 테이블의 모든 내용 조회
CREATE PROC p_select_all
AS
BEGIN
	select * from testTable
END

 

  • p_select_id : 해당 테이블의 특정 아이디의 정보 조회
    • 입력 파라미터 존재
CREATE PROC p_select_id
	@a int
AS
BEGIN
	select * from testTable where id = @a
END

 

  • p_select_address : 해당 테이블의 특정 지역에 대한 멤버 이름 조회
    • 입력 파라미터, 출력 파라미터 존재
CREATE PROC p_select_address
	@address NVARCHAR(MAX),
	@outValue NVARCHAR(MAX) OUT
AS
BEGIN
	select @outValue = username from testTable where address = @address
END

파라미터가 없는 프로시저의 모든 값 출력

프로시저명 : p_select_all

 

EntityManager em = JpaUtils.getEntityManager();

/* 입출력 파라미터가 없는 프로시저 */
System.out.println("************************************************************");
System.out.println("입출력 파라미터가 없는 프로시저 호출하기");
System.out.println("테이블의 모든 데이터에 대한 조회 결과 확인");

// 저장 프로시저 쿼리, 저장 프로시저의 이름 입력
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("p_select_all", ProcedureResultSet.class);

// 쿼리의 결과를 리스트의 형태로 반환
List<ProcedureResultSet> resultList = storedProcedure.getResultList();

// 쿼리 결과를 저장할 변수 선언
ArrayList<ProcedureResultSet> resultAll  = new ArrayList<>();

int i=0; // Object Index
for ( ProcedureResultSet row : resultList ) {
    // 저장
    resultAll.add(row);

    // 값 확인
    System.out.println("    프로시저 처리 결과 : " + (i+1) + " row = "
            + resultAll.get(i).getUsername() + ", "
            + resultAll.get(i).getAddress());
    i++;
}

em.close();

입력 파라미터가 있는 프로시저 값 출력

EntityManager em = JpaUtils.getEntityManager();

/* 입력 파라미터가 있는 프로시저 */
System.out.println("************************************************************");
System.out.println("입력 파라미터가 있는 프로시저 호출하기");
System.out.println("입력 파라미터는 특정 ID를 입력하여 해당 ID의 정보 확인");

// 저장 프로시저 쿼리, 저장 프로시저의 이름 입력
StoredProcedureQuery storedProcedureOnlyInput = em.createStoredProcedureQuery("p_select_id", ProcedureResultSet.class);

// 저장 프로시저의 입력 파라미터 설정
storedProcedureOnlyInput.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);

// 저장 프로시저의 입력 파라미터 입력(순서, 값)
storedProcedureOnlyInput.setParameter(1, 2);

// 쿼리의 결과를 리스트의 형태로 반환
List<ProcedureResultSet> result = storedProcedureOnlyInput.getResultList();

int j=0; // Object Index
for ( ProcedureResultSet row : result ) {
    // 값 확인
    System.out.println("    프로시저 처리 결과 : 입력한 ID(2), 조회 결과 : "
            + result.get(j).getUsername() + ", "
            + result.get(j).getAddress());
    j++;
}

em.close();

입출력 파라미터가 모두 있는 프로시저 값 출력

EntityManager em = JpaUtils.getEntityManager();

/* 출력 파라미터가 있는 프로시저 */
System.out.println("************************************************************");
System.out.println("출력 파라미터가 있는 프로시저 호출하기");
System.out.println("출력 파라미터는 특정 지역에 거주하는 사용자의 이름을 반환");

// 저장 프로시저 쿼리, 저장 프로시저의 이름 입력
StoredProcedureQuery storedProcedureOutput = em.createStoredProcedureQuery("p_select_address");

// 저장 프로시저의 입력, 출력 파라미터 설정
storedProcedureOutput.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
storedProcedureOutput.registerStoredProcedureParameter(2, String.class, ParameterMode.OUT);

// 저장 프로시저의 입력 파라미터 입력(순서, 값)
storedProcedureOutput.setParameter(1, "incheon");

// 출력 파라미터의 값 저장
String outputParam = (String) storedProcedureOutput.getOutputParameterValue(2);

// 출력 파라미터의 값 확인
System.out.println("    프로시저 처리 결과 : 입력한 지역 = incheon, 출력 파라미터의 값 = " + outputParam);
System.out.println("************************************************************");

em.close();

실행 결과


프로젝트 디렉토리 구조 및 전체 소스 코드

프로젝트 디렉토리 구조


소스 코드

config.JpaUtils

package org.example.config;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class JpaUtils {
    private static final String PERSISTENCE_UNIT_NAME = "myPersistenceUnit"; // replace with your persistence unit name

    private static final EntityManagerFactory emFactory;
    static {
        emFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
    }

    public static EntityManager getEntityManager() {
        return emFactory.createEntityManager();
    }
}

config.JpaQuery

package org.example.config;

import jakarta.persistence.EntityManager;
import jakarta.persistence.ParameterMode;
import jakarta.persistence.StoredProcedureQuery;
import org.example.entity.ProcedureResultSet;

import java.util.ArrayList;
import java.util.List;

public class JpaQuery {
    private static List<ProcedureResultSet> executeNamedQuery() {
        EntityManager em = JpaUtils.getEntityManager();

        /* 입출력 파라미터가 없는 프로시저 */
        System.out.println("************************************************************");
        System.out.println("입출력 파라미터가 없는 프로시저 호출하기");
        System.out.println("테이블의 모든 데이터에 대한 조회 결과 확인");

        // 저장 프로시저 쿼리, 저장 프로시저의 이름 입력
        StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("p_select_all", ProcedureResultSet.class);

        // 쿼리의 결과를 리스트의 형태로 반환
        List<ProcedureResultSet> resultList = storedProcedure.getResultList();

        // 쿼리 결과를 저장할 변수 선언
        ArrayList<ProcedureResultSet> resultAll  = new ArrayList<>();

        int i=0; // Object Index
        for ( ProcedureResultSet row : resultList ) {
            // 저장
            resultAll.add(row);

            // 값 확인
            System.out.println("    프로시저 처리 결과 : " + (i+1) + " row = "
                    + resultAll.get(i).getUsername() + ", "
                    + resultAll.get(i).getAddress());
            i++;
        }


        /* 입력 파라미터가 있는 프로시저 */
        System.out.println("************************************************************");
        System.out.println("입력 파라미터가 있는 프로시저 호출하기");
        System.out.println("입력 파라미터는 특정 ID를 입력하여 해당 ID의 정보 확인");

        // 저장 프로시저 쿼리, 저장 프로시저의 이름 입력
        StoredProcedureQuery storedProcedureOnlyInput = em.createStoredProcedureQuery("p_select_id", ProcedureResultSet.class);

        // 저장 프로시저의 입력 파라미터 설정
        storedProcedureOnlyInput.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);

        // 저장 프로시저의 입력 파라미터 입력(순서, 값)
        storedProcedureOnlyInput.setParameter(1, 2);

        // 쿼리의 결과를 리스트의 형태로 반환
        List<ProcedureResultSet> result = storedProcedureOnlyInput.getResultList();

        int j=0; // Object Index
        for ( ProcedureResultSet row : result ) {
            // 값 확인
            System.out.println("    프로시저 처리 결과 : 입력한 ID(2), 조회 결과 : "
                    + result.get(j).getUsername() + ", "
                    + result.get(j).getAddress());
            j++;
        }


        /* 출력 파라미터가 있는 프로시저 */
        System.out.println("************************************************************");
        System.out.println("출력 파라미터가 있는 프로시저 호출하기");
        System.out.println("출력 파라미터는 특정 지역에 거주하는 사용자의 이름을 반환");

        // 저장 프로시저 쿼리, 저장 프로시저의 이름 입력
        StoredProcedureQuery storedProcedureOutput = em.createStoredProcedureQuery("p_select_address");

        // 저장 프로시저의 입력, 출력 파라미터 설정
        storedProcedureOutput.registerStoredProcedureParameter(1, String.class, ParameterMode.IN);
        storedProcedureOutput.registerStoredProcedureParameter(2, String.class, ParameterMode.OUT);

        // 저장 프로시저의 입력 파라미터 입력(순서, 값)
        storedProcedureOutput.setParameter(1, "incheon");

        // 출력 파라미터의 값 저장
        String outputParam = (String) storedProcedureOutput.getOutputParameterValue(2);

        // 출력 파라미터의 값 확인
        System.out.println("    프로시저 처리 결과 : 입력한 지역 = incheon, 출력 파라미터의 값 = " + outputParam);
        System.out.println("************************************************************");


        em.close();
        return null;
    }

    public static List<ProcedureResultSet> doNameQuery() {
        return executeNamedQuery();
    }

}

entity.ProcedureResultSet

package org.example.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
@Table(name="testTable")
public class ProcedureResultSet {
    @Id
    private int id;
    @Column
    private String username;
    @Column
    private String address;
}

Main

package org.example;

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

import static org.example.config.JpaQuery.doNameQuery;

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
        // 쿼리 실행
        doNameQuery();
    }
}
반응형