我可以使用 MySQL Connector/J 执行多个用分号分隔的查询吗? [复制]

Posted

技术标签:

【中文标题】我可以使用 MySQL Connector/J 执行多个用分号分隔的查询吗? [复制]【英文标题】:Can I execute multiple queries separated by semicolon with MySQL Connector/J? [duplicate] 【发布时间】:2013-09-02 03:41:50 【问题描述】:

我的 mysql db 的 jdbc 驱动程序是 5.1.25 版本。

我想像这样执行 sql 查询:

statement.execute("select fullName from user where user_id=1; select fullName from user where user_id=2");

而且我总是收到异常:

Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select fullName from user where user_id=2' at line 1
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
    at com.mysql.jdbc.Util.getInstance(Util.java:386)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4187)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4119)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2570)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2731)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2809)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2758)
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:894)
    at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:732)
    at dbViewer.model.UserConnectionManager.retrieveRoutinesNames1(UserConnectionManager.java:622)
    at dbViewer.model.UserConnectionManager.main(UserConnectionManager.java:637)

但是当我从命令行运行相同的查询(以分号分隔)时,它可以完美运行并按预期输出两个表。

【问题讨论】:

可能不会——sql 会返回两个结果集,execute() 会返回什么?如果您只有一个语句,大概一切正常? 在一个查询中禁止多个语句也是一种安全保障,尽管它不是完美的。如果您可以执行多个查询,则注入可以让入侵者执行完全任意的 SQL:xkcd.com/327。你应该做select fullName from user WHERE user_id=1 OR user_id=2。您还应该使用准备好的语句,以提高效率和安全性以防止 SQL 注入。 【参考方案1】:

在大多数数据库的查询中使用; 不起作用,因为它通常不是语句语法本身的一部分,而是命令行或脚本输入到单独语句的终止符。命令行或脚本处理器将分号视为语句已完成并可发送到服务器的信号。

同样在 JDBC 中,单个语句准备(或执行)应该只是 一个 实际语句,因此不允许多个语句,因此也不需要分号,至于一些(大多数?)数据库分号不是语句语法的一部分,包含它只是一个语法错误。

如果要执行多个语句,则需要使用单独的执行。从技术上讲,MySQL 确实有一个选项来支持可以通过连接属性启用的多个执行。此行为不符合 JDBC 规范/API,并且使您的代码的可移植性降低。见allowMultiQueriesDriver/Datasource Class Names, URL Syntax and Configuration Properties for Connector/J

【讨论】:

【参考方案2】:

我想像这样执行 sql 查询:

statement.execute("select fullName from user where user_id=1; select fullName from user where user_id=2");

这只有在您设置了一个数据库连接属性以允许同时执行多个查询时才有可能。并且属性名称是allowMultiQueries=true。必须设置此属性并将其与数据库连接请求一起发送到服务器。一般语法是这样的:

String dbUrl = "jdbc:mysql:///test?allowMultiQueries=true";

这是对那些已经存在的附加连接属性,例如autoReConnect=true 等。

allowMultiQueries 属性的可接受值为 truefalseyesno。任何其他值在运行时都会被 SQLException 拒绝。

您必须使用execute( String sql ) 或其其他变体来获取查询执行的结果。

multiQuerySqlString =  "select fullName from user where user_id=1; ";
multiQuerySqlString += "select fullName from user where user_id=2; ";
// you can multiple types of result sets
multiQuerySqlString += "select last_login from user_logs where user_id=1; ";

boolean hasMoreResultSets = stmt.execute( multiQuerySqlString );

要遍历和处理结果,您需要以下步骤:

int rsNumber = 0;
while ( hasMoreResultSets )   
    rsNumber += 1;
    Resultset rs = stmt.getResultSet();

    // based on the structure of the result set,
    // you can handle column values.
    if ( rsNumber == 1 ) 
      while( rs.next() ) 
          // handle your rs here
       // while rs
     // if rs is 1
    else if ( rsNumber == 2 ) 
      // call a method using this rs.
      processMyResultSet( rs ); // example
     // if rs is 2
    // ... etc

    // check whether there exist more result sets  
    hasMoreResultSets = stmt.getMoreResults();  
 // while results

参考

Multiple queries executed in java in single statement SO 上的类似帖子之一,我对此给出了答案。

【讨论】:

【参考方案3】:

不,你不能。您希望通过调用 statement.execute(...) 得到什么? 它返回一个 ResultSet(... 这意味着一个表)。

您只需调用“select fullName from user where user_id in (1, 2)”即可返回两个结果。

在 JDBC 语句中使用分号通常很容易出错。一些 JDBC 驱动程序不支持这一点(例如,如果您使用“;”关闭 SQL 语句,IBM 的 DB2 10.x 的 JDBC 驱动程序会引发异常)。

【讨论】:

这不是真的。 JDBC 可以为一个语句/查询返回多个结果集。您使用 statement.getResultSet() 获取当前结果集, statement.next() 移动到下一个。您需要将 allowMultiQueries 属性设置为 true 以禁用 JDBC 保护措施,因为允许分号会打开 SQL 注入攻击向量。

以上是关于我可以使用 MySQL Connector/J 执行多个用分号分隔的查询吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在 MySQL 中通过 Connector/J 使用 getGeneratedKeys 和批量插入

没有使用 MySQL Connector/J 的服务器端准备语句

如何使 MySQL Connector/J 在 android 上工作?

在 Windows 7 中设置路径 Connector/J

与 MySql 的连接正在自动中止。如何正确配置Connector/J?

与 MySql 的连接正在自动中止。如何正确配置Connector/J?