“?”附近的 MySQLSyntaxErrorException尝试执行 PreparedStatement 时
Posted
技术标签:
【中文标题】“?”附近的 MySQLSyntaxErrorException尝试执行 PreparedStatement 时【英文标题】:MySQLSyntaxErrorException near "?" when trying to execute PreparedStatement 【发布时间】:2010-11-09 06:36:44 【问题描述】:我正在尝试使用 Java 中的 PreparedStatement 执行查询。
我在尝试执行查询时收到错误号 1064(语法错误)。
我已经在 mysql 查询浏览器中使用替代值对此进行了测试,效果很好。
我的代码有什么问题?
以下是相关代码:
String query = "select MemberID, MemberName from members where MemberID = ? or MemberName = ?";
Connection conn = DriverManager.getConnection(DATABASE_URL, USERNAME, PASSWORD);
PreparedStatement s = conn.prepareStatement(query);
s.setInt(1, 2);
s.setString(2, "zen");
ResultSet rs = s.executeQuery(query);
这是我得到的例外:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 你有一个 SQL 语法错误;检查与您对应的手册 MySQL 服务器版本,以便在 '? 附近使用正确的语法或会员名 = ?'在第 1 行
【问题讨论】:
给出更多关于“错误”的细节 - Java 中的异常有堆栈跟踪 就在调用 executeQuery 之前,我在调试期间看到参数被替换到 PreparedStatemet 中,查询变为“com.mysql.jdbc.JDBC4PreparedStatement@6e9770a3: select MemberID, MemberName from members where MemberID = 2 或 MemberName = 'zen'" 好吧,你已经提供了你的全部代码。这就是没有人回答的原因——太长了。隔离相关位并仅显示它们。 【参考方案1】:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以了解在 '? 附近使用的正确语法。或 MemberName = ?'在第 1 行
MySQL 不理解 SQL 查询中?
的含义。这确实是无效的 SQL 语法。所以不知何故它没有被PreparedStatement
取代。你猜怎么着?
PreparedStatement s = conn.prepareStatement(query);
s.setInt(1, intValue);
s.setString(2, strValue);
rs = s.executeQuery(query); // Fail!
您正在用原始查询覆盖准备好的查询!您需要调用无参数的PreparedStatement#executeQuery()
方法而不是Statement#executeQuery(String)
。
PreparedStatement s = conn.prepareStatement(query);
s.setInt(1, intValue);
s.setString(2, strValue);
rs = s.executeQuery(); // OK!
与问题无关,您的代码正在泄漏资源。几个小时后数据库将用完它们,您的应用程序将崩溃。要解决此问题,您需要遵循 JDBC 习惯用法,在获取它们的 try
块的 finally
块中关闭 Connection
、Statement
和 ResultSet
。查看JDBC basic tutorial了解更多详情。
【讨论】:
这只是一个家庭作业,而且我截断了我的大部分代码,我确实有一个关闭所有相关资源的方法。我试过 executeQuery() 它现在可以工作了,谢谢:P【参考方案2】:如果您查看 Statement
(PreparedStatement
的超类)的 javadocs,executeQuery(String)
和 executeUpdate(String)
的方法文档会这样说:
注意:不能在
PreparedStatement
或CallableStatement
上调用此方法。
这就是你在这里所做的:在 PreparedStatement
对象上从 Statement
调用 executeQuery(String)
。
现在由于 javadocs 说你“不能”这样做,你得到的实际行为是未指定的......并且可能依赖于 JDBC 驱动程序。在这种情况下,您使用的 MySQL 驱动程序似乎将其解释为意味着您正在将更新作为非准备语句进行,因此?
标记不会被解释为参数占位符。这会导致服务器端 SQL 解析器说“语法错误”。
(如果您这样做,如果 MySQL 驱动程序抛出不同的未经检查的异常,程序员会更容易;例如 UnsupportedOperationException
。但是,标准 JDBC javadocs 没有说明在这种情况下应该发生什么。它由供应商决定他们的驱动程序会做什么。)
【讨论】:
JDBC 规范确实说明了应该发生的情况:应该抛出SQLException
:" SQLException - 如果发生数据库访问错误,则在关闭的语句上调用此方法,给定的 SQL语句生成除单个 ResultSet 对象之外的任何内容,在 PreparedStatement 或 CallableStatement 上调用该方法"。但是,MySQL 驱动程序只是在这种情况下“偶然”执行此操作(如果传递的语句没有参数占位符,它将与规范相反)。旧的 JDBC 规范(IIRC JDBC 3 和更早的版本)没有这个要求。以上是关于“?”附近的 MySQLSyntaxErrorException尝试执行 PreparedStatement 时的主要内容,如果未能解决你的问题,请参考以下文章