MySQL Connector/J能否执行多个以分号分隔的查询?

10

我的MySQL数据库的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()方法要返回什么?如果只有一个语句的话,这大概都没有问题。 - Dave Richardson
禁止在一个查询中使用多个语句也是一种安全保障,尽管不是完美的。如果您可以执行多个查询,则注入可能会让入侵者执行完全任意的SQL:http://xkcd.com/327。您应该执行`select fullName from user WHERE user_id=1 OR user_id=2`。您还应该使用准备好的语句,以提高效率并防止SQL注入。 - yshavit
3个回答

18
在大多数数据库中,在查询中使用;不起作用,因为它通常不是语句语法的一部分,而是用于分隔命令行或脚本输入的终止符。命令行或脚本处理器将半角分号视为语句完成的信号,然后将其发送到服务器。
此外,在JDBC中,单个语句的准备(或执行)应该只有一个实际语句,所以不允许使用多个语句,并且对于一些(大多数?)数据库来说,分号不是语句语法的一部分,将其包含在内只会导致语法错误。
如果要执行多个语句,需要使用单独的执行。从技术上讲,MySQL确实有一个选项来支持多个执行,可以通过连接属性启用。这种行为不符合JDBC规范/API,并且使您的代码不够可移植。请参见Connector/J的驱动程序/数据源类名称、URL语法和配置属性上的allowMultiQueries

12

我想执行以下的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

参考


-1

不行。调用statement.execute(...)能得到什么?它只会返回一个ResultSet(也就是一个表)。

你可以直接调用"select fullName from user where user_id in (1, 2)",以获得两个结果。

JDBC语句中加分号通常很容易出错。有些JDBC驱动程序不支持这个特性(例如,IBM的DB2 10.x JDBC驱动程序如果在SQL语句末尾加上";",就会抛出异常)。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接