可以在Java JPA 2.1中将空参数传递给存储过程吗?

前端之家收集整理的这篇文章主要介绍了可以在Java JPA 2.1中将空参数传递给存储过程吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
使用新的JPA 2.1 stored procedure调用,有没有办法传递null参数?

以下是一个示例用法

StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("get_item",Item.class);
storedProcedure.registerStoredProcedureParameter(0,String.class,ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter(1,ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter(2,Timestamp.class,ParameterMode.IN);

storedProcedure.setParameter(0,a);
storedProcedure.setParameter(1,b);
storedProcedure.setParameter(2,c);

storedProcedure.execute();

当所有参数都被给出时,这个工作起作用,但是当c为空时,它会失败并出现(Postgresql)JDBC驱动程序的错误.

Caused by: org.postgresql.util.PsqlException: No value specified for parameter 2
at org.postgresql.core.v3.SimpleParameterList.checkAllParameteRSSet(SimpleParameterList.java:216) [postgresql-9.3-1101.jdbc41.jar:]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:244) [postgresql-9.3-1101.jdbc41.jar:]
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:559) [postgresql-9.3-1101.jdbc41.jar:]
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417) [postgresql-9.3-1101.jdbc41.jar:]
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:410) [postgresql-9.3-1101.jdbc41.jar:]
    at org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.execute(WrappedPreparedStatement.java:404)
    at org.hibernate.result.internal.OutputsImpl.<init>(OutputsImpl.java:69) [hibernate-core-4.3.1.Final.jar:4.3.1.Final]
    ... 244 more

我也考虑过使用我自己的类传递参数,例如:

storedProcedure.registerStoredProcedureParameter(0,InputParameters.class,ParameterMode.IN);
storedProcedure.setParameter(0,inputParameters);

这失败了:

Caused by: java.lang.IllegalArgumentException: Type cannot be null

我猜是因为它需要一个可以映射到sql类型的类型.

有没有办法传递null参数?

解决方法

这是Hibernate 4.3的与JPA 2.1相关的发现.

如果DB不支持默认参数,则会抛出异常:

ProcedureCall procedure = getSession().createStoredProcedureCall("my_procedure");

procedure.registerParameter("my_nullable_param",ParameterMode.IN)
         .bindValue(null);

// execute
procedure.getOutputs();

从Hibernate的源码将参数绑定到底层CallableStatement:

public abstract class AbstractParameterRegistrationImpl {

  ..

  @Override
  public void prepare(CallableStatement statement,int startIndex) throws sqlException {

    if ( mode == ParameterMode.INOUT || mode == ParameterMode.IN ) {
      if ( bind == null || bind.getValue() == null ) {
        // the user did not bind a value to the parameter being processed.  That might be ok *if* the
        // procedure as defined in the database defines a default value for that parameter.
        // Unfortunately there is not a way to reliably know through JDBC Metadata whether a procedure
        // parameter defines a default value.  So we simply allow the procedure execution to happen
        // assuming that the database will complain appropriately if not setting the given parameter
        // bind value is an error.
        log.debugf("Stored procedure [%s] IN/INOUT parameter [%s] not bound; assuming procedure defines default value",procedureCall.getProcedureName(),this);
      } else {
         typeToUse.nullSafeSet( statement,bind.getValue(),startIndex,session() );
      }
    }
  }

  ..
}

以上评论如下:

The user did not bind a value to the parameter being processed. That
might be ok if the procedure as defined in the database defines a
default value for that parameter. Unfortunately there is not a way to
reliably know through JDBC Metadata whether a procedure parameter
defines a default value. So we simply allow the procedure execution
to happen assuming that the database will complain appropriately if
not setting the given parameter bind value is an error.

我正在解释为JPA(特别是Hibernate)不支持设置空参数.看起来他们正在努力支持默认参数值,而在适当时替换空值.他们选择支持前者.看起来像后者需要支持(可空值)必须使用java.sql.CallableStatement:

getSession().doWork(new Work() {

  @Override
  public void execute(Connection conn) throws sqlException {

    CallableStatement stmt = conn.prepareCall("{ call my_prodecure(:my_nullable_param) }");

    if(stringVariableThatIsNull != null) {
       stmt.setString("my_nullable_param",stringVariableThatIsNull);
    } else {
       stmt.setNull("my_nullable_param",Types.VARCHAR);
    }

    stmt.execute();
    stmt.close();

  }    
});

tl; dr我们仍然被迫处理低级JDBC,因为JPA或Hibernate似乎没有处理可空参数.它们支持过程参数默认值,而不是替换空值.

原文链接:https://www.f2er.com/java/124518.html

猜你在找的Java相关文章