首页 > 解决方案 > 如何使用 jdbctemplate 从 Java 执行匿名 PL/SQL

问题描述

我想从 Java 调用这个查询(在 SQL 开发人员上运行时有效)

DECLARE
    TYPE my_id_tab IS
        TABLE OF my_table.my_id%TYPE;
    my_ids  my_id_tab;
BEGIN
    UPDATE my_table
        SET
            another_id = NULL
    WHERE
        another_id IS NULL
        AND   create_datetime BETWEEN '03-JUN-19' AND '05-JUN-19'
    RETURNING my_id BULK COLLECT INTO my_ids;

    COMMIT;
END;

但我相信 Java 在试图弄清楚我希望 my_ids 的集合返回给我时遇到了困难。

这是我到目前为止尝试过的异常消息,java.sql.SQLException: Invalid column index 例如 java.sql.SQLException: operation not allowed: Ordinal binding and Named binding cannot be combined!

final Connection connection = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());

      try (final CallableStatement callableStatement = connection.prepareCall(TEST_SQL))
      {
         callableStatement.registerOutParameter("my_ids", Types.ARRAY);
         callableStatement.executeUpdate();
         int[] arr = (int[]) callableStatement.getArray("my_ids").getArray();
         return Arrays.stream(arr).boxed().collect(Collectors.toSet());
      }
      catch (final SQLException e)
      {
         LOG.info("threw exception, {}", e);
      }
      finally
      {
         DataSourceUtils.releaseConnection(connection, jdbcTemplate.getDataSource());
      }

标签: javaoracleplsqljdbctemplate

解决方案


这不是最简单的事情,但它很容易做到。您需要在 Oracle 中创建一个 TYPE 来定义结果。

对于此演示,创建并填充 EMP 和 DEPT:EMP 和 DEPT 脚本

创建TYPE, 需要定义将返回的数组:

create type t_integer_array as table of integer;

我们将运行以下命令UPDATE,它只会更新几行:

UPDATE emp
   SET job = job        -- a nonsense update
 WHERE comm IS NOT NULL -- only affect some of the rows

这是Java:

package test;

import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Types;
import java.util.Arrays;

public class OracleTest {

  public static void main(String[] args) {
    try {
      Class.forName("oracle.jdbc.driver.OracleDriver");
      Connection conn = DriverManager.getConnection(
              "<your JDBC url>", "<your user>", "<your password>");

      // Prepare the call, without defining the the output variable
      // in a DECLARE section of the PL/SQL itself, you just need to
      // include a "?" and then associate the correct type in the
      // next step.
      CallableStatement cs = conn.prepareCall(
                "BEGIN\n"
              + "  UPDATE emp\n"
              + "     SET job = job\n"
              + "   WHERE comm is not null\n"
              + "  RETURNING empno BULK COLLECT INTO ?;\n"
              + "END;");

      // Register the single OUT parameter as an array, using the 
      // type that was defined in the database, T_INTEGER_ARRAY.
      cs.registerOutParameter(1, Types.ARRAY, "T_INTEGER_ARRAY");
      cs.execute();

      // Now get the array back, as array of BigDecimal.
      // BigDecimal is used because it doesn't have precision 
      // problems like floating point, it will contain all digits
      // that the database provided.
      BigDecimal[] nums = (BigDecimal[]) (cs.getArray(1).getArray());
      System.out.println(Arrays.toString(nums));
      cs.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

这是我的输出:

[7499、7521、7654、7844]

这些是empno仅受更新影响的行的技术密钥 ( )。


推荐阅读