可以在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() ); } } } .. } 以上评论如下:
我正在解释为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似乎没有处理可空参数.它们支持过程参数默认值,而不是替换空值. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |