概要
JPAでストアドプロシージャ(SQLServer)から複数のResultSetを受け取る方法です。
実装内容
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.microsoft.sqlserver:mssql-jdbc'
}
シンプルなストアドの例
- SingleStoredProcedureはINPUTパラメータ名がParameterで、1つのResultSetを返却します。
public interface SingleStoredProcedureRepository extends JpaRepository<SingleStoredProcedureResult, Long> {
@Procedure(procedureName = "SingleStoredProcedure")
List<SingleStoredProcedureResult> executeSingleStoredProcedure(@Param("Parameter") String parameter);
}
ResultSetを2つ返すストアドから取得する例
- MultipleResutSetStoredProcedureは以下の通りです。
- INPUTパラメータ名は InParameter
- OUTPUTパラメータ名は OutParameter
- INOUTPUTパラメータ名は InOutParameter
- ResultSetは以下の2つを返却
- FirstResult (詳細はFirstResult.java参照)
- SecondResult (詳細はSecondResult.java参照)
public class MultipleResutSetStoredProcedureRepository {
@PersistenceContext(unitName = "db")
private EntityManager entityManager;
public MultipleResutSetStoredProcedureResult executeMultipleResutSetStoredProcedure(
String inParameter,
String inoutParameter){
entityManager.createStoredProcedureQuery("MultipleResutSetStoredProcedure", FirstResult.class)
.registerStoredProcedureParameter("InParameter", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("OutParameter", String.class, ParameterMode.OUT)
.registerStoredProcedureParameter("InOutParameter", String.class, ParameterMode.INOUT)
.setParameter("InParameter", inParameter)
.setParameter("InOutParameter", inOutParameter); // 1
procedureQuery.execute(); // 2
String outParameter = (String)procedureQuery.getOutputParameterValue("OutParameter"); // 3
inoutParameter = (String)procedureQuery.getOutputParameterValue("InOutParameter"); // 4
List<FirstResult> firstResultList = procedureQuery.getResultList(); // 5
entityManager.createStoredProcedureQuery("MultipleResutSetStoredProcedure", SecondResult.class)
.registerStoredProcedureParameter("InParameter", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("OutParameter", String.class, ParameterMode.OUT)
.registerStoredProcedureParameter("InOutParameter", String.class, ParameterMode.INOUT)
.setParameter("InParameter", inParameter)
.setParameter("InOutParameter", inOutParameter); // 6
procedureQuery.hasMoreResults(); // 7
List<SecondResult> secondResultList = procedureQuery.getResultList(); // 8
return new MultipleResutSetStoredProcedureResult(outParameter, inoutParameter, firstResultList, secondResultList);
}
}
FirstResult.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class FirstResult {
@Id
@Column(name = "id")
private Long id;
@Column(name = "first_name")
private String firstName;
}
SecondResult.java
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class SecondResult {
@Id
@Column(name = "id")
private Long id;
@Column(name = "second_type")
private String secondType;
@Column(name = "second_name")
private String secondName;
}
処理の流れとしては以下の通りです。
- ストアドプロシージャの1つ目のResultSetを受け取るクラスを指定して、IN、OUT、INOUTパラメータを設定する
- ストアドプロシージャを実行する(procedureQuery.execute())
- OutParameterを取得する
- InOutParameterを取得する
- 1つ目のResultSetを取得する
- ストアドプロシージャの2つ目のResultSetを受け取るクラスを指定して、IN、OUT、INOUTパラメータを設定する
- ストアドプロシージャを実行する(procedureQuery.hasMoreResults())
- 2つ目のResultSetを取得する
メソッド名から6.の処理なしで2つ目のResultSetを取得できるようなイメージでしたが、取得できませんでした。
また、1.の第二引数は、複数のクラスを指定できるため、1つ目と2つ目のResultSetを指定して実行(procedureQuery.execute())しましたが、エラーになってしまいました。
注意点
JPAで複数のResultSetを返却するストアドプロシージャの実行例は上記の通りですが、実際に動作してみると
- procedureQuery.execute()
- procedureQuery.hasMoreResults()
の2箇所でDBアクセスをしています。
上記は、これまで紹介したコードを実際に動作させてAPMで取得した図です。
一番下の紫の部分がDBアクセスとなっており、左から1番目がSingleStoredProcedureを実行したものです。
2、3番目はMultipleResutSetStoredProcedureを実行したものです。
DBアクセスを1回にしたい場合は、別の方法で検証する必要がありそうです。