简体   繁体   English

从 java 调用 Postgres 存储过程,要返回的表

[英]Postgres stored procedure call from java, table to return

I made a Postgres stored procedure:我做了一个 Postgres 存储过程:

CREATE OR REPLACE FUNCTION GetUser(ipUserId integer)
RETURNS setof users AS $$
BEGIN
  IF ipUserId is null THEN
    return query select * from users A order by modifieddate desc;
  END IF;
  return query select * from users where iduser = ipUserId;
END;
$$ LANGUAGE plpgsql;

I tried to use it in java like this:我尝试在 java 中使用它,如下所示:

    StoredProcedureQuery query = entityManager.createStoredProcedureQuery("GetUser").
            registerStoredProcedureParameter("ipUserId",
                    Integer.class, ParameterMode.IN)
            .registerStoredProcedureParameter("users",
                    List.class, ParameterMode.OUT)
            .setParameter("postId", 1);

or或者

 StoredProcedureQuery query = entityManager.createStoredProcedureQuery("GetUser")
                .registerStoredProcedureParameter(1,void.class, ParameterMode.REF_CURSOR)
                .registerStoredProcedureParameter(2,Integer.class, ParameterMode.IN)
                .setParameter(2, ipIdUser);

I want to store the result in a List.我想将结果存储在列表中。

What and how should i do, because i'm getting all kind of errors?我应该怎么做,因为我遇到了各种各样的错误?

Update:更新:

Those are the errors:这些是错误:

javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: Error calling CallableStatement.getMoreResults
Caused by: org.hibernate.exception.SQLGrammarException: Error calling CallableStatement.getMoreResults
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.result.internal.OutputsImpl.convert(OutputsImpl.java:79)
    at org.hibernate.result.internal.OutputsImpl.<init>(OutputsImpl.java:56)
    at org.hibernate.procedure.internal.ProcedureOutputsImpl.<init>(ProcedureOutputsImpl.java:34)
    at org.hibernate.procedure.internal.ProcedureCallImpl.buildOutputs(ProcedureCallImpl.java:453)
    at org.hibernate.procedure.internal.ProcedureCallImpl.getOutputs(ProcedureCallImpl.java:404)
    at org.hibernate.procedure.internal.ProcedureCallImpl.outputs(ProcedureCallImpl.java:663)
    at org.hibernate.procedure.internal.ProcedureCallImpl.getResultList(ProcedureCallImpl.java:751)
    ... 21 more
Caused by: org.postgresql.util.PSQLException: A CallableStatement was executed with an invalid number of parameters

You can try using CallableStatement. 您可以尝试使用CallableStatement。 Assuming that your Connection var is OK: 假设您的Connection变量正常:

CallableStatement stmt = con.prepareCall("{call SCHEMA.PROCEDURE_NAME (?, ?)}");
stmt.setInt(1, custom_var);
stmt.registerOutParameter(2, OracleTypes.INTEGER);
stmt.execute();

To get result: stmt.getInt(3); stmt.getString(4) 要获得结果: stmt.getInt(3); stmt.getString(4) stmt.getInt(3); stmt.getString(4)

If you can't succeed try using JdbcTemplate: 如果无法成功,请尝试使用JdbcTemplate:

SimpleJdbcCall call = new SimpleJdbcCall(this.jdbcTemplate).withSchemaName(SCHEMA).withProcedureName(PROC);
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("ipUserId", custom_var);
Map out = call.execute(params);

To get single result: Integer.parseInt("" + out.get("OUT_PARAM_NAME")); (String) out.get("OUT_PARAM_NAME2")); 要获取单个结果: Integer.parseInt("" + out.get("OUT_PARAM_NAME")); (String) out.get("OUT_PARAM_NAME2")); Integer.parseInt("" + out.get("OUT_PARAM_NAME")); (String) out.get("OUT_PARAM_NAME2"));

Or you can save all the result in a list to work on it later: 或者,您可以将所有结果保存在列表中以供日后使用:

SimpleJdbcCall call = new SimpleJdbcCall(this.jdbcTemplate);
List<Map<String, Object>> rows = call.getJdbcTemplate().queryForList(PROC_STRING, new Object[] { param1, param2 });

I found a much simple solution, just make a SQL Query to call the procedure with hibernate. 我找到了一个非常简单的解决方案,只需执行一个SQL查询以使用hibernate调用该过程即可。

    String SqlString = "select * from GetUser({0})";

    if (ipIdUser == null )
        SqlString = MessageFormat.format(SqlString, "NULL");
    else
        SqlString = MessageFormat.format(SqlString, ipIdUser);

    LOGGER.info("SqlSting =" + SqlString);

    return entityManager.createNativeQuery(SqlString, User.class)
            .getResultList();

Why not use getResultList on StoredProcedureQuery ? 为什么不对StoredProcedureQuery使用getResultList This avoids having to do the string manipulation. 这避免了必须进行字符串操作。

List<User> users = entityManager.createStoredProcedureQuery("GetUser")
  .registerStoredProcedureParameter("ipUserId", Integer.class, ParameterMode.IN)
  .setParameter("ipUserId", ipIdUser)
  .getResultList();

In your case, you have a table valued function that happens to map to an actual table, so the approach using the JPA native query is elegant too, but perhaps your projection is something different, or you return multiple nested data structures, arrays, etc, where working with JPA might be tricky. In your case, you have a table valued function that happens to map to an actual table, so the approach using the JPA native query is elegant too, but perhaps your projection is something different, or you return multiple nested data structures, arrays, etc ,使用 JPA 可能会很棘手。

jOOQ generates code for all of your procedures, including table valued functions . jOOQ 为您的所有过程生成代码,包括表值函数 For example, you'll have a Routines class containing a getUser method, which you can query like this:例如,您将有一个包含getUser方法的Routines class,您可以像这样查询:

Result<GetUser> result = Routines.getUser(configuration, 1);

You can also use the table valued function as an actual table in the query, like this:您还可以使用表值 function 作为查询中的实际表,如下所示:

Result<GetUser> result = ctx.selectFrom(GETUSER(1)).fetch();

Disclaimer: I work for the company behind jOOQ.免责声明:我在 jOOQ 背后的公司工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM