【问题标题】:simpleJdbcCall calling Pl/SQL procedure -- ORA-22922 nonexistent LOB valuesimpleJdbcCall 调用 Pl/SQL 过程 -- ORA-22922 不存在的 LOB 值
【发布时间】:2021-11-24 01:08:50
【问题描述】:

我收到此 SQLException -- ORA-22922 不存在的 LOB 值。

我的情况是:

  1. 我正在调用一个采用结构数组的过程,
  2. 结构体包含三种类型,两种是日期,一种是Clob
  3. 当我使用 Spring 的 simpleJdbcCall 设置 null 而不是 clob 执行该过程时,将执行语句并将数据写入数据库。
  4. 这表明我的 simpleJdbcCall 设置正确。

这是我创建 clob、array 和 struct 并执行 simpleJdbCall 的代码。

  public void insertRecords(List<MyObject> objectList) throws Exception {
    Array array = null;
    Connection connection = jdbcTemplate.getDataSource().getConnection();
    OracleConnection oracleConnection = connection.unwarp(OracleConnection.class);

    Object[] arrObj = new Object[objectList.size()];
    Object[][] structObj = new Object[objectList.size()][3];

    Clob clob = connection.createClob();
    for(int loop = 0; loop < objectList.size(); loop++) {
       clob.setString(objectList.get(loop).getData);

       structObj[loop][0] = objectList.getDate1();
       structObj[loop][1] = objectList.getDate2();
       structObj[loop][2] = clob; //null; 

       arrObj[loop] = oracleConnection.createStruct(structName, structObj[loop]);
     }

     array = oracleConnection.createOracleArray(collectionName, arrObj);

     Map<String, Array> inparam = new HashMap<~>;

     inparam.put(arrayParamString, array);

     //procInsertData is a SimpleJdbcCall
     procInsertData.exexute(inparam);
     clob.free();
  }

意见和解决方案请...

更新:2014 年 5 月 5 日(调试 SQL 语句日志输出):

2014-05-05 11:30:18,126 [main] DEBUG  SimpleJdbcCall - JdbcCall call not compiled    before execution - invoking compile
2014-05-05 11:30:18,296 [main] DEBUG  SimpleJdbcCall - Compiled stored procedure. Call string is [{call MY_DB.WRITE(?)}]
2014-05-05 11:30:18,357 [main] DEBUG  SimpleJdbcCall - SqlCall for procedure [write] compiled
2014-05-05 11:30:18,367 [main] DEBUG  SimpleJdbcCall - The following parameters are used for call {call MY_DB.WRITE(?)} with:  {in_my_objects=org.springframework.jdbc.core.SqlParameterValue@7e4034bd}
2014-05-05 11:30:18,367 [main] DEBUG  SimpleJdbcCall - 1: in_my_objects SQL Type 2003 Type Name MY_OBJECT_COLL org.springframework.jdbc.core.SqlParameter
2014-05-05 11:30:18,388 [main] DEBUG  StatementCreatorUtils - Overriding type info with runtime info from SqlParameterValue: column index 1, SQL type 2003, type name null
2014-05-05 11:30:18,388 [main] TRACE  StatementCreatorUtils - Setting SQL statement parameter value: column index 1, parameter value [oracle.sql.ARRAY@61d6687a], value class [oracle.sql.ARRAY], SQL type 2003
2014-05-05 11:30:18,447 [main] INFO   XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
2014-05-05 11:30:18,623 [main] INFO   SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{call MY_DB.WRITE(?)}]; SQL  state [99999]; error code [22922]; ORA-22922: nonexistent LOB value
ORA-06512: at "PKG.MY_DB", line 30
ORA-06512: at line 1
; nested exception is java.sql.SQLException: ORA-22922: nonexistent LOB value
ORA-06512: at "PKG.MY_OBJ", line 30
ORA-06512: at line 1

【问题讨论】:

  • 我不认为 4. 是 3. 的有效结论。如果 Spring 只是省略了您设置为 null 的 LOB 插入参数怎么办? insert into t (a,b) values...insert into t (a,b,lob) values... 完全不同。您是否启用了调试日志记录以查看哪些 SQL 语句对数据库有问题?
  • 感谢@MarcelStör 的输入,我已经尝试在Oracle 上测试插入数据的过程并且它正在工作。此外,在上面的代码中,当创建 struct 时,在创建 db 中的 struct 对象之前会检查这些输入类型。不确定如何在 Spring/Java 端启用调试登录。任何指针?
  • @MarcelStör 添加了调试日志

标签: java oracle jdbctemplate clob


【解决方案1】:

Clob 实例与您用来创建它的“oracleConnection”相关联,SimpleJDBCCall 使用另一个连接进行 DB 调用。从数据库的角度来看,有两个独立的会话,这就是 SimpleJDBCCall 使用的会话中不存在 clob 的原因。

SimpleJDBCCall 使用的连接必须用于 Clob 创建。

我通过实现 SQLData 和提取当前连接设法解决了类似的问题:

Map<String, Object> values = new HashMap<>();
values.put("IN_bean_type", new MyBean());
simpleJdbcCallOperations.execute(values);

我的豆子:

class MyBean implements SQLData {
    ...
    @Override
    public void writeSQL(SQLOutput stream) throws SQLException {
        ...
        Clob clob = ((OracleSQLOutput)stream).getSTRUCT().getJavaSqlConnection().createClob(); //hack to get the current connection
        clob.setString(1, "stringValue");
        stream.writeClob(clob);
        ...
    }
    ...
}

【讨论】:

    【解决方案2】:

    我在这里面临同样的问题,但仅在尝试使用 StoredProcedure 执行此操作时

    但是这样

            conn = datsource.getConnection();
            cstmt = conn.prepareCall("{? = call schema.package.function(?)}");
            cstmt.registerOutParameter(1, Types.CLOB);
            cstmt.setClob(2, clob);
            cstmt.execute();
    

    工作得很好。

    【讨论】:

      【解决方案3】:

      我遇到了类似的问题。你可以纠正它。我做出了自己的贡献,希望它可以为您服务。

      public PreparedStatement insertaReprocesos(TimerLog timer, List<ReprocesosDTO> listaInsertaProcesos) throws SQLException, Exception{
          Connection conexion = null;
          CallableStatement cstmt = null;
          String query = null;
          try {
              conexion = JDBCUtils.getConnection(UtilProperties.DATASOURCE);
              Connection conexion2 = JDBCUtils.getImplementsConnectionAllServer(conexion);
              query= UtilProperties.SP_INSERTA_REPROCESOS;
              cstmt = conexion.prepareCall(query);
              Object[] recordArray = new Object[6];
              Struct[] structs = new Struct[listaInsertaProcesos.size()];
              int registroCont = 0;
              Clob myClob = conexion2.createClob();
              for(ReprocesosDTO registro : listaInsertaProcesos) {
                  Reader reader = registro.getFcregistro().getCharacterStream();//esta variable la esta declarada como Clob
                  BufferedReader br = new BufferedReader(reader);
                  myClob.setString(1, br.readLine());
                  
                      recordArray[0] = registro.getFiprocesoId();
                      recordArray[1] = registro.getFdfecha();
                      recordArray[2] = (registro.getFisecuencia());
                      recordArray[3] = registro.getFistatusid();
                      recordArray[4] = myClob;// este dato en BD esta declarado como CLOB
                      recordArray[5] = registro.getFcusuario();
                      structs[registroCont++] = conexion2.createStruct(UtilProperties.TYP_REPORTE_PROCESOS, recordArray);
              }
              Array oracleRecord = ((OracleConnection) conexion2).createOracleArray(UtilProperties.TYPE_TAREPORTE,structs);
              cstmt.setArray(1, oracleRecord);
              cstmt.registerOutParameter(MonitorConstants.PA_CODIGO_SALIDA_2,OracleTypes.VARCHAR);
              cstmt.registerOutParameter(MonitorConstants.PA_MENSAJE_SALIDA_3,OracleTypes.VARCHAR);
              
              cstmt.execute();
          } catch (SQLException e) {
              LOGGER.error("Mensaje "+e.getMessage()+"Causa: "+e.getCause());
              timer.setTiempoParcial(MonitorConstants.MONITOR_DAO, MonitorConstants.INSERTA_PROCESOS);
              throw new SQLException(e);
          } catch (Exception e) {
              timer.setTiempoParcial(MonitorConstants.MONITOR_DAO, MonitorConstants.INSERTA_PROCESOS);
              throw new Exception(e);
          }
          return cstmt;
      }
      

      【讨论】:

      • 请用英文提问。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 2015-01-08
      • 2016-12-25
      相关资源
      最近更新 更多