PreparedStatement 参数索引超出范围

huangapple go评论61阅读模式
英文:

PreparedStatement parameter index out of range

问题

I am getting a parameter index out of range error when executing a prepared statement. I have several other statements working correctly. The only difference with this query is it's the only UPDATE. The rest are all INSERT, ADD, DELETE etc. Any guidance on what I may be doing wrong would be greatly appreciated.

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();

Error:

java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 1).

I have put a couple print statements in the middle of the code block and it seems to fail on the 3rd parameter. All values coming in are valid and match the types being assigned. MySQL is being used and the statement works fine if executed in the console.

Thank you for reading and any help you can provide.

Edit: Here is the statement handler method I am using as well. I am combing through to see what else I should add to help get this thing figured out. Thank you for the comments!

public class StatementHandler {

/**

  • create a statement reference
    */
    private static PreparedStatement preparedStatement;

/**

  • method to create a statement object
    */
    public static void setPreparedStatement(Connection connection, String sqlStatement) throws SQLException {
    preparedStatement = connection.prepareStatement(sqlStatement);
    }

/**

  • getter to return a statement object
    */
    public static PreparedStatement getPreparedStatement(){
    return preparedStatement;
    }
    }
英文:

I am getting a parameter index out of range error when executing a prepared statement. I have several other statements working correctly. The only difference with this query is it's the only UPDATE. The rest are all INSERT, ADD, DELETE etc. Any guidance on what I may be doing wrong would be greatly appreciated.

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();

Error:

java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 1).

I have put a couple print statement sin the middle of the code block and it seems to fail on the 3rd parameter. All values coming in are valid and match the types being assigned. MySQL is being used and the statement works fine if executed in the console.

Thank you for reading and any help you can provide.

Edit: Here is the statement handler method I am using as well. I am combing through to see what else I should add to help get this thing figured out. Thank you for the comments!

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;
    }
}

答案1

得分: 0

您的代码片段并不清晰,但我可以猜测。我将列出我所得出的一系列结论;您需要仔细检查这些:

  1. StatementHandler是一个类(不是一个变量)。(原因:您将它大写了)。
  2. setPreparedStatement和getPreparedStatement是StatementHandler类中的静态方法。(自然而然地遵循)。
  3. 您正在使用多个线程(原因:这足以解释这个问题)。
  4. 您没有进行同步(原因:与#3相同)。

然后,这个结果显而易见:您不能这样做。您的整个虚拟机(VM)只有一个全局的“prepared statement”,多个线程以更或少任意的顺序调用setPreparedStatement和getPreparedStatement。一个线程调用setPreparedStatement,然后另一个线程也这样做,然后第一个尝试获取另一个线程设置的prepared statement,一切都乱七八糟了。

您不能以这种方式做。事实上,您甚至不能在两个线程之间共享连接(因为它们会相互干扰并破坏您的事务)。

如果您不太了解static的作用(而且诚然,这是一个稍微高级的话题),那就永远不要使用它。您几乎可以在不使用静态方法的情况下编写所有您想要的Java代码。唯一的例外是public static void main必须是静态的,但只需将其写成一行代码:new MyClass().go();,其中go()是一个非静态方法,您就可以开始了。

英文:

Your snippet doesn't make it clear, but I can guess. I'll list a series of conclusions I'm drawing; you'd have to doublecheck these:

  1. StatementHandler is a class (not a variable). (reason: You've capitalized it).
  2. setPreparedStatement and getPreparedStatement are static methods in the StatementHandler class. (follows naturally).
  3. You are using multiple threads (reason: That would be sufficient to explain this problem).
  4. You aren't synchronizing (reason: Same as #3).

Then this result is obvious: You can't do that. Your entire VM has one global 'prepared statement' with multiple threads calling setPreparedStatement and getPreparedStatement in more or less arbitrary orders. One thread calls setPreparedStatement, then another thread does, then the first tries to get the prepared statement the other one set, and it all goes to hades in a handbasket.

You can't do it this way. Heck, you can't even share a connection between two threads (as they'd be getting in each other's way and messing up your transactions).

If you don't quite get what static does (And it is, admittedly, a bit of an advanced topic), don't ever use it. You can pretty much write all the java you'd ever want without using static methods. The one exception is public static void main which must be static, but just make that the one-liner: new MyClass().go();, with go() being a non-static method, and you're good to go.

答案2

得分: 0

我想进一步超越rzwitserloot,并假设您的AddressDAO也使用了StatementHandler。

AddressDAO.getAddressId(address)的查询可能有一个参数,与异常中的1相匹配,并在设置第三个参数之前替换了prepared statement。

作为证据,将AddressDAO.getAddressId(address)分配给一个变量(然后在设置prepared statement之前使用它)将足够。

或者,您可以将prepared statement存储在一个变量中,然后在之后使用这个变量。

英文:

I'd like to go one step further than rzwitserloot and presume that your AddressDAO uses StatementHandler, too.

The query for AddressDAO.getAddressId(address) has probably one parameter, which matches the 1 from the Exception, and replaces the prepredStatemt before setting the third parameter.

As proof it would be suffient assigning AddressDAO.getAddressId(address) to a variable(and use it afterwards) before setting the prepared statement.

Alternativly you can get once the prepared statement in a variable and use this variable afterwards.

huangapple
  • 本文由 发表于 2020年8月10日 21:25:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63341154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定