将空列表发送到存储过程

时间:2016-07-28 14:13:13

标签: java oracle stored-procedures mybatis empty-list

我在oracle中创建了一个自定义类型,如下所示。

create or replace TYPE  "ABC_OBJECT"  AS OBJECT (
   ticket_no  VARCHAR2(50),
);

create or replace TYPE "ABC_OBJECT_LIST"  IS TABLE OF ABC_OBJECT;

ABC_OBJECT_LIST类型用作存储过程中输入字段的数据类型。我从我的java代码调用存储过程。我编写了一个自定义TypeHandler来处理列表类型输入并传递给存储过程。一切正常,我能够将我的值发送到存储过程并使用处理程序中的下面的代码成功检索它们。

    @Override
    public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType arg3) throws SQLException {
      List<Object> object = (List<Object>)parameter;
      structDescriptor = getStructureDescriptor(con, PASSENGER_DETAILS_JDBC_OBJECT);
      arrayDescriptor = getJDBCArrayDescriptor(con, PASSENGER_DETAILS_JDBC_OBJECT_LIST);

      STRUCT[] structs = new STRUCT[objects.size()];
      for (int index = 0; index < objects.size(); index++) {
        structs[index] = getJDBCDataObject(structDescriptor, con, objects.get(index));
      }

      ARRAY oracleArray = getJDBCArrayObject(arrayDescriptor, con, structs);
      ps.setArray(i, oracleArray);
    }

    private STRUCT getJDBCDataObject(final StructDescriptor structDescriptor, final Connection con, final Object object) {
    STRUCT struct = null;
    Object[] params = new Object[1];
    params[0] = "This is test text";


    struct = getJDBCStructureObject(structDescriptor, con, params);
    return struct;
  }


  private STRUCT getJDBCStructureObject(final StructDescriptor structDescriptor, final Connection con,
      final Object[] params) {
    STRUCT struct = null;
    try {
      struct = new STRUCT(structDescriptor, con, params);
    } catch (SQLException e) {
      LOG.error("Error in creating JDBC structure Object.", e);
    }
    return struct;
  }

  private ARRAY getJDBCArrayObject(final ArrayDescriptor arrayDescriptor, final Connection con,
      final STRUCT[] structs) {
    ARRAY oracleArray = null;
    try {
      oracleArray = new ARRAY(arrayDescriptor, con, structs);
    } catch (SQLException e) {
      LOG.error("Error in creating JDBC Array Object.", e);
    }
    return oracleArray;
  }

但这只有在我发送列表中的至少一个对象时才有效。如果我尝试发送空列表,我会收到以下错误。

Caused by: org.springframework.jdbc.UncategorizedSQLException: Could not set parameters for mapping:

我用谷歌搜索并找到了使用下面的解决方案。

preparedStatement.setNull(i, Types.ARRAY);

但这也不起作用。我也尝试在我的存储过程中定义DEFAULT NULL,但这也没有用。也试过以下。

preparedStatement.setArray(i, new ARRAY(arrayDescriptor, con, new STRUCT[]{null}));

这给出了错误或无效的参数异常。还试过以下。

preparedStatement.setNull(i,Types.Array, "ABC_OBJECT_LIST");

并低于错误。

Caused by: org.springframework.jdbc.BadSqlGrammarException: 
### Error querying database.  Cause: java.sql.SQLException:ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'PROCESSAUTOTICKETING'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

我用谷歌搜索但主要找到原始类型的解决方案,如整数,字符串等但不是List,我发现的解决方案(setNull)没有用。

我正在使用MyBatis(注释)来调用存储过程。有没有办法处理这个以发送null作为输入或可能是存储过程的空白列表。

1 个答案:

答案 0 :(得分:0)

我在一长串热门和试用选项之后终于解决了这个问题。解决方案是在Oracle Type中定义NULL,如下所示。

create or replace TYPE  "ABC_OBJECT"  AS OBJECT (
   ticket_no  VARCHAR2(50) NULL,
);

create or replace TYPE "ABC_OBJECT_LIST"  IS TABLE OF ABC_OBJECT NULL;

这允许在typehandler中传递null,如下所示

preparedStatement.setArray(i, new ARRAY(arrayDescriptor, con, null));

如果java代码中的列表为空,则可以将null传递给存储过程。

希望这能节省一些人的时间。