使用JPA存储存储过程返回值

时间:2018-05-09 05:48:00

标签: sql-server spring-boot stored-procedures spring-data-jpa

我试图使用JPA(和Spring Boot 2)来执行SQL Server存储过程。这是程序:

CREATE Procedure [dbo].[GetStatus] 
@statusId   char(32),
@bar    int
AS
BEGIN TRY
    SELECT IIF(COUNT(1)>0 , 1, 0)   FROM Status WITH (NOLOCK) 
    WHERE statusId = @statusId AND bar = @bar
END TRY
BEGIN CATCH
    EXEC EventLog @@PROCID
END CATCH
GO

我试图捕获返回值,但无法找到方法。我的实体是:

@Entity
@Table(name = "status")
@NamedStoredProcedureQueries({
        @NamedStoredProcedureQuery(name = "getStatusByStatusId",
                procedureName = "GetStatus",
                parameters = {
                        @StoredProcedureParameter(mode = ParameterMode.IN, name = "statusId", type = String.class),
                        @StoredProcedureParameter(mode = ParameterMode.IN, name = "bar", type = Integer.class)                    })
})
public class Status implements Serializable {
    @Id
    @GeneratedValue
    private Long id;
    private Integer bar;
    private String statusId;
    private Date createDate;
}

我的存储库是:

@Repository
public interface StatusRepository extends JpaRepository<Status, Long> {
    @Procedure("GetStatus")
    int getStatusByStatusId(@Param("statusId") String statusId, @Param("bar") Integer bar);
}

当我从服务层运行此方法时,出现错误:

  

&#34;未为存储过程定义参数输出...&#34;

我尝试添加参数(通过命名计数并键入为Integer)。我尝试了List,Object []但没有任何效果。 唯一有用的是如果我更改存储库方法以返回void。但在那种情况下,我无法获得返回值。 所以,我的问题是如何获得SELECT值?任何帮助表示赞赏。我的app.yml有:

  datasource:
    driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
    url: jdbc:sqlserver://dev.lsd.com:1433;databaseName=Qrex;integratedSecurity=true;MultiSubnetFailover=true;authenticationScheme=JavaKerberos
    username:
    password:
  jpa:
    hibernate:
      ddl-auto: none
      naming:
        physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    show-sql: true
    database-platform: org.hibernate.dialect.SQLServerDialect
    database: sql_server

我的gradle依赖是:

compile "com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8"

1 个答案:

答案 0 :(得分:0)

我不相信JPA可以处理返回任意数量的结果集和/或更新计数和/或错误消息的存储过程。我见过的所有例子都相当简单。您的程序返回:

  • 包含投影(不是实体!)
  • 的结果集
  • 无论EventLog程序返回什么。可能是任何事情

以下是如何直接使用JDBC(没有OUT个参数,所以普通的PreparedStatement会这样做。

以下是如何仅使用JDBC获取一个结果集:

try (PreparedStatement stmt = connection.prepareStatement(
    "EXEC [GetStatus] ?, ?"
)) {
    stmt.setString(1, statusId);
    stmt.setInt(2, bar);

    if (stmt.execute()) {
        try (ResultSet rs = stmt.getResultSet()) {
            // Do your thing
        }
    }
}

以下是如何获取任意数量的结果集

如果你想要检索EventLog产生的任何内容,你可能更愿意这样做:

try (PreparedStatement stmt = connection.prepareStatement(
    "EXEC [GetStatus] ?, ?"
)) {
    stmt.setString(1, statusId);
    stmt.setInt(2, bar);

    fetchLoop:
    for (int i = 0, updateCount = 0; i < 256; i++) {
        boolean result = (i == 0)
            ? s.execute()
            : s.getMoreResults();

        if (result)
            try (ResultSet rs = s.getResultSet()) {
                System.out.println("Result      :");

                while (rs.next())
                    System.out.println("  " + rs.getString(1));
            }
        else if ((updateCount = s.getUpdateCount()) != -1)
            System.out.println("Update Count: " + updateCount);
        else
            break fetchLoop;
    }
}

I've described this approach of fetching arbitrary result sets and update counts more in detail here,特别是如何正确获取异常和警告。

如果使用该方法,您可能希望将该逻辑包装在某些库代码中。

使用jOOQ

还有可能使用jOOQ来做这些事情(免责声明:我为供应商工作),如果你可以致电:

Results results = ctx.fetchMany("EXEC [GetStatus] ?, ?", statusId, bar);

获取org.jooq.Results类型,包含交错结果集,更新计数,例外和警告