ORA-01745: invalid host/bind variable name

近期,有一个批量插入的sql,突然报出错误“ORA-01745: invalid host/bind variable name(无效的主机/绑定变量名称错误)”。 字面意思排查,可能原因是:使用了保留字、多余或者缺少冒号或者逗号等等语句的问题。

经过仔细核对和测试,单条插入都可以正常执行,所以考虑是不是条数太多的问题。所以临时将插入操作改为批次执行,暂时解决了问题。

那么,真相到底是怎样呢?

我们先来还原一下当时的场景:

mybatis xml 语句


        insert into tDETAIL (
        NO, AMOUNT, BALANCE,
        TYPE, MAC, TAG, ORDERID,BATCHNO
        )
        (
        
            select
            #{item.no,jdbcType=VARCHAR},
            #{item.amount,jdbcType=NUMERIC},
            #{item.balance,jdbcType=NUMERIC},
            #{item.type,jdbcType=VARCHAR},
            #{item.mac,jdbcType=VARCHAR},
            #{item.tag,jdbcType=VARCHAR},
            #{item.orderid,jdbcType=VARCHAR},
            #{item.batchno,jdbcType=VARCHAR}
            from dual
        
        )
    

后来经过查阅资料,发现根本原因是由于sql语句包含了太多的“?”(占位符),超出了Oracle的限制。经过验证,当占位符数量超过65536时,就会报出异常。

/**
 * Constructs a query using '?' for placeholders and using
 * as many of these as specified with the int parameter.
 *
 * @param numberPlaceholders Number of placeholders ('?')
 *    to include in WHERE clause of constructed query.
 * @return SQL Query that has provided number of '?" placeholders.
 */
private String buildQuery(final int numberPlaceholders)
{
   final StringBuilder builder = new StringBuilder();
   builder.append("SELECT region_id FROM countries WHERE ");
   for (int count=0; count < numberPlaceholders-1; count++)
   {
      builder.append("region_id = ? OR ");
   }
   builder.append("region_id = ?");
   return builder.toString();
}
/**
 * Execute the provided query and populate a PreparedStatement
 * wrapping this query with the number of integers provided
 * as the second method argument.
 * 
 * @param query Query to be executed.
 * @param numberValues Number of placeholders to be set in the
 *    instance of {@code PreparedStatement} used to execute the
 *    provided query.
 */
private void executeQuery(final String query, final int numberValues)
{
   try (final Connection connection = getDatabaseConnection();
        final PreparedStatement statement = connection.prepareStatement(query))
   {
      for (int count = 0; count < numberValues; count++)
      {
         statement.setInt(count+1, count+1);
      }
      final ResultSet rs = statement.executeQuery();
      while (rs.next())
      {
         out.println("Region ID: " + rs.getLong(1));
      }
   }
   catch (SQLException sqlException)
   {
      out.println("ERROR: Unable to execute query - " + sqlException);
   }
}

参考:https://dzone.com/articles/too-many-preparedstatement-placeholders-in-oracle

你可能感兴趣的:(ORA-01745: invalid host/bind variable name)