PreparedStatement 不适用于 Java 中的 Sybase IQ
Posted
技术标签:
【中文标题】PreparedStatement 不适用于 Java 中的 Sybase IQ【英文标题】:PreparedStatement Does Not Work For Sybase IQ In Java 【发布时间】:2019-05-28 16:02:01 【问题描述】:我和我的团队遇到了一个问题。我们正在尝试从 Sybase IQ 数据库中检索一些数据,并使用where
子句过滤并获取特定数据。
SQL 已经过测试并且工作正常,但在使用 Prepared Statement 时会失败。
测试完成:
-
如果我们运行查询(带或不带 where 子句参数),它工作正常。
如果我们使用在 Prepared Statement 中硬编码的参数运行查询,它也可以正常工作。
如果我们以编程方式设置预处理语句的参数,它就不起作用。
以上测试确认 JDBC 连接工作正常。
使用 PreparedStatement、JdbcTemplate 或 NamedParameterJdbcTemplate 时会出现相同的错误,因此我怀疑 PreparedStatement 和 Sybase IQ 之间可能存在问题。
有人可以帮忙调查一下吗?我们已经找到了一种解决方法,但是知道为什么这不起作用会非常有用。
我在同一问题上发现了非常相似的主题 (How do I execute PreparedStatement(select object_id()) in sybase iq?),但没有人在那里提供可接受且正确的答案,因此我决定为此创建一个新问题。
使用的代码是:
Class.forName("com.sybase.jdbc4.jdbc.SybDriver");
PreparedStatement stmt = con.prepareStatement("select * from myView where off = ? and acc = ?");
stmt.setString(1, "260");
stmt.setString(2, "9050V");
ResultSet set = stmt.executeQuery();
错误信息是:
Exception in thread "main" java.sql.SQLException: JZ0SA: Prepared Statement: Input parameter not set, index: 0.
at com.sybase.jdbc4.jdbc.SybConnection.getAllExceptions(Unknown Source)
at com.sybase.jdbc4.jdbc.SybStatement.handleSQLE(Unknown Source)
at com.sybase.jdbc4.jdbc.SybStatement.sendQuery(Unknown Source)
at com.sybase.jdbc4.jdbc.SybPreparedStatement.sendQuery(Unknown Source)
at com.sybase.jdbc4.jdbc.SybStatement.executeQuery(Unknown Source)
at com.sybase.jdbc4.jdbc.SybPreparedStatement.executeQuery(Unknown Source)
使用的 JDBC 驱动程序(Maven 依赖):
<dependency>
<groupId>com.sybase</groupId>
<artifactId>jconn4</artifactId>
<version>7.0</version>
</dependency>
【问题讨论】:
请添加执行语句。 虽然 JDBC 驱动程序应该对参数使用基于 1 的索引(JDBC 规范要求),但您是否尝试过使用基于 0 的索引(因为错误消息也使用基于 0 的索引)?在任何情况下,您都应该使用完整的异常堆栈跟踪更新您的问题,并指定您的 Sybase 驱动程序和 Sybase 服务器的 完整 版本。 您使用哪个 JDBC 驱动程序进行连接? 编辑了问题。是的,我尝试过使用基于 0 的索引 - 抛出了 ArrayOutOfBoundsException,因此必须使用基于 1 的索引。 来自您发布的代码:select * from view where off = ? and acc = ?
。 view
是数据库表吗? off
和acc
的数据类型是什么?
【参考方案1】:
我在使用 sybase iq 时遇到了同样的问题。
我在preparedStatement.execureQuery()
语句之前添加了以下两行代码来解决这个问题。
preparedStatement.setFetchSize(Integer.MAX_VALUE);
preparedStatement.setFetchDirection(ResultSet.FETCH_FORWARD);
不确定这样做是否正确,但确实有效。
或
你可以设置
preparedStatement.setCursorName("SomeCursorName");
这也解决了这个问题。
但在多线程环境下,您需要设置一个唯一的游标名称。可能正在使用随机数或其他东西,并且不要创建太多游标,将它们限制为将同时执行的并发线程数。
【讨论】:
【参考方案2】:我使用了 jconn4 连接属性 LITERAL_PARAMS=true,它运行良好。小心,性能应该会受到影响。
当设置为“true”时,PreparedStatement 接口中的 setXXX 方法设置的任何参数都会在执行时插入到 SQL 语句中。如果设置为“false”,则在 SQL 语句中保留参数标记,并将参数值单独发送到服务器。
【讨论】:
这也解决了我使用 Sybase SQL Anywhere DB 的问题【参考方案3】:stmt.setString(1, "260"); stmt.setString(2, "9050V");
数组索引以0开头不是吗?在您使用的 API 中,它不是基于零的索引吗?
【讨论】:
根据 Java 文档,PreparedStatement 索引从 1 开始 - 请参阅 docs.oracle.com/javase/7/docs/api/java/sql/… 这是一个答案吗?这应该是评论吗?以上是关于PreparedStatement 不适用于 Java 中的 Sybase IQ的主要内容,如果未能解决你的问题,请参考以下文章
ResultSet.getNext() 不适用于 PreparedStatement
PreparedStatement 不适用于 Java 中的 Sybase IQ
htaccess 重定向适用于邮递员而不适用于 chrome (CORS)
Prepared Statement 中的绑定不适用于 Microsoft SQL Server JDBC 驱动程序 sqljdbc4.jar