将空列表发送到存储过程

Sending empty list to stored procedure

我在 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

我用谷歌搜索,但大部分找到了原始类型的解决方案,如 Integer、String 等,但没有找到 List,而且我找到的解决方案 (setNull) 没有用。

我正在使用MyBatis(annotation)调用存储过程。有什么方法可以处理此问题以将 null 作为输入发送,或者可能是存储过程的空白列表。

经过一长串点击和试用选项后,我终于解决了这个问题。解决方案是在 Oracle 类型中定义 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;

这允许在类型处理程序中的数组中传递空值,如下所示

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

如果列表在 java 代码中为空,这允许将 null 传递给存储过程。

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