PreparedStatement 参数索引超出范围
Posted
技术标签:
【中文标题】PreparedStatement 参数索引超出范围【英文标题】:PreparedStatement parameter index out of range 【发布时间】:2020-08-10 13:25:20 【问题描述】:在执行准备好的语句时出现参数索引超出范围错误。我还有其他几个正常工作的语句。此查询的唯一区别是它是唯一的 UPDATE。其余的都是 INSERT、ADD、DELETE 等。任何关于我可能做错的指导将不胜感激。
sqlStatement = "UPDATE customer SET customerName = ?, addressId = ? WHERE customerId = ?;";
StatementHandler.setPreparedStatement(ConnectionHandler.connection, sqlStatement);
StatementHandler.getPreparedStatement().setString(1, name);
StatementHandler.getPreparedStatement().setInt(2, AddressDAO.getAddressId(address));
StatementHandler.getPreparedStatement().setInt(3, customerId);
StatementHandler.getPreparedStatement().executeUpdate();
错误:
java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 1).
我在代码块中间放了几个打印语句,它似乎在第三个参数上失败了。所有传入的值都是有效的,并且与分配的类型相匹配。正在使用 mysql,如果在控制台中执行,该语句可以正常工作。
感谢您的阅读以及您能提供的任何帮助。
编辑:这也是我正在使用的语句处理程序方法。我正在梳理,看看我还应该添加什么来帮助解决这个问题。谢谢你们的cmets!
public class StatementHandler
/**
* create statement reference
*/
private static PreparedStatement preparedStatement;
/**
* method to create statement object
*/
public static void setPreparedStatement(Connection connection, String sqlStatement) throws SQLException
preparedStatement = connection.prepareStatement(sqlStatement);
/**
* getter to return statement object
*/
public static PreparedStatement getPreparedStatement()
return preparedStatement;
【问题讨论】:
看来StatementHandler.getPreparedStatement()
每次都返回的不是同一个实例,你能添加这个方法的代码吗?还要记住,如果 StatementHandler
被不同的线程调用,准备好的语句对象很可能在两个 getPreparedStatement()
调用之间被替换。
请提供minimal reproducible example。
【参考方案1】:
你的 sn-p 没有说清楚,但我可以猜到。我将列出我正在得出的一系列结论;您必须仔细检查这些:
-
StatementHandler 是一个类(不是变量)。 (原因:你已经大写了)。
setPreparedStatement 和 getPreparedStatement 是 StatementHandler 类中的静态方法。 (自然而然)。
您正在使用多个线程(原因:这足以解释此问题)。
您没有同步(原因:与 #3 相同)。
那么这个结果很明显:你不能那样做。您的整个 VM 有一个全局“准备好的语句”,其中多个线程以或多或少的任意顺序调用 setPreparedStatement 和 getPreparedStatement。一个线程调用 setPreparedStatement,然后另一个线程调用,然后第一个线程尝试获取另一个设置的准备好的语句,这一切都交给了哈迪斯。
你不能这样做。哎呀,你甚至不能在两个线程之间共享连接(因为它们会互相妨碍并弄乱你的事务)。
如果您不太了解 static 的作用(诚然,它是一个高级主题),请永远不要使用它。您几乎可以在不使用静态方法的情况下编写所有您想要的 java。一个例外是public static void main
,它必须是静态的,但只需将其设为单行:new MyClass().go();
,其中 go() 是一种非静态方法,您就可以开始了。
【讨论】:
【参考方案2】:我想比 rzwitserloot 更进一步,并假设您的 AddressDAO
也使用 StatementHandler。
AddressDAO.getAddressId(address)
的查询可能有一个参数,它与 Exception 中的 1 匹配,并在设置第三个参数之前替换 preredStatemt。
作为证明,在设置准备好的语句之前将 AddressDAO.getAddressId(address)
分配给一个变量(然后使用它)就足够了。
或者,您可以在变量中获取准备好的语句,然后使用该变量。
【讨论】:
以上是关于PreparedStatement 参数索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章
FLUTTER:RangeError(索引):索引超出范围:没有有效索引:0(通过参数)
指数超出范围。必须是非负数且小于集合的大小。 (参数'索引')'
错误:索引超出范围。必须是非负数且小于集合的大小。参数名称:索引