【问题标题】:JDBC mysql does not support placeholder of LIMIT in PreparedStatement?JDBC mysql不支持PreparedStatement中的LIMIT占位符?
【发布时间】:2016-01-12 12:51:38
【问题描述】:

我使用mysql-connector-java-5.1.38在Windows 10 64位上操作mysql-community-5.7.10.0。

我尝试在limit 中绑定值以进行分页

"SELECT * FROM employee LIMIT ?, ?"

但是结果显示:

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 '?, ?' at line 1
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
    at com.mysql.jdbc.Util.getInstance(Util.java:387)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:939)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2547)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2505)
    at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1370)
    at SqlTest.main(SqlTest.java:65)

不过,我直接在navicat中试了sql,却能得到正确答案:

INSERT INTO employee VALUES (1, 'Zara');
INSERT INTO employee VALUES (2, 'Zara');
INSERT INTO employee VALUES (3, 'Zara');
INSERT INTO employee VALUES (4, 'Zara');
SET @skip=1; SET @numrows=5;
PREPARE STMT FROM 'SELECT * FROM employee LIMIT ?, ?';
EXECUTE STMT USING @skip, @numrows;

这是我的全部代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SqlTest {
  // JDBC driver name and database URL
  static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
  static final String DB_URL = "jdbc:mysql://localhost:3306/employee?useServerPrepStmts=false";
  // Database credentials
  static final String USER = "root";
  static final String PASS = "whaty123";

  static final int PAGESIZE = 10;

  public static void main(String[] args) {
    Connection conn = null;
    Statement stmt = null;
    PreparedStatement pStmt = null;

    // STEP 2: Register JDBC driver
    try {
      Class.forName("com.mysql.jdbc.Driver");
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    }

    // STEP 3: Open a connection
    System.out.println("Connecting to database...");
    try {
      conn = DriverManager.getConnection(DB_URL, USER, PASS);
    } catch (SQLException e) {
      e.printStackTrace();
    }

    String insertPreparedSql = "INSERT INTO employee " + "VALUES (?, 'Zara')";

    try {
      pStmt = conn.prepareStatement(insertPreparedSql);
    } catch (SQLException e) {
      e.printStackTrace();
    }

    for (int i = 0; i < 100; i++) {
      try {
        pStmt.setInt(1, i);
        pStmt.execute();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }

    String selectLimitSql = "SELECT * FROM employee LIMIT ?, ?";
    // select with limit
    try {
      pStmt = conn.prepareStatement(selectLimitSql);
      pStmt.setFetchSize(PAGESIZE);
      pStmt.setMaxRows(PAGESIZE);
      pStmt.setFetchDirection(ResultSet.FETCH_FORWARD);
      int pageNo = 0;
      pStmt.setInt(1, pageNo * PAGESIZE);
      pStmt.setInt(2, PAGESIZE);
      ResultSet rs = pStmt.executeQuery(selectLimitSql);
      while (!rs.wasNull()) {
        while(rs.next()) {
          System.out.println("id: " + String.valueOf(rs.getInt(1)) + " name: " + rs.getString(2));
        }
        pageNo = pageNo + 1;
        pStmt.setInt(1, pageNo * PAGESIZE);
        pStmt.setInt(2, PAGESIZE);
        pStmt.executeQuery(selectLimitSql);
      }
      rs.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

}

【问题讨论】:

  • 13.2.9 SELECT Syntax 中,它说在准备好的语句中,可以使用 LIMIT 指定参数?占位符标记。 @Abhik Chakraborty

标签: java mysql jdbc prepared-statement


【解决方案1】:

您的问题LIMIT 的语法或 MySQL 支持无关,因为它受到支持。问题在于您执行PreparedStatement 的方式。

在使用PreparedStatement 时,您可能不会使用executeQuery(String sql),因为您之前已经为执行准备了SQL 字符串,无需在executeQuery() 方法中再次传递它。这样做吧

ResultSet rs = pStmt.executeQuery();

而不是

ResultSet rs = pStmt.executeQuery(selectLimitSql);

再次传递selectLimitSql(如上行),您将忽略以下行:

pStmt.setInt(1, pageNo * PAGESIZE);
pStmt.setInt(2, PAGESIZE);

这就像执行包含 '?, ?' 占位符的原始纯 sql,然后您会遇到该异常。

【讨论】:

    【解决方案2】:

    您不需要传递查询字符串。这样做

     ResultSet rs = pStmt.executeQuery();
    

    而不是

    ResultSet rs = pStmt.executeQuery(selectLimitSql);
    

    此外,请删除以下行,因为在查询本身中会处理 limit 的分页。

    pStmt.setFetchSize(PAGESIZE);
    pStmt.setMaxRows(PAGESIZE);
    pStmt.setFetchDirection(ResultSet.FETCH_FORWARD);
    

    以下代码有效:

        import java.sql.Connection;
        import java.sql.DriverManager;
        import java.sql.PreparedStatement;
        import java.sql.ResultSet;
        import java.sql.SQLException;
        import java.sql.Statement;
    
        public class SqlTest {
          // JDBC driver name and database URL
          static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
          static final String DB_URL = "jdbc:mysql://localhost:3306/company?useServerPrepStmts=false";
          // Database credentials
          static final String USER = "root";
          static final String PASS = "rohan";
    
          static final int PAGESIZE = 10;
    
          public static void main(String[] args) {
            Connection conn = null;
            Statement stmt = null;
            PreparedStatement pStmt = null;
    
            // STEP 2: Register JDBC driver
            try {
              Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
              e.printStackTrace();
            }
    
            // STEP 3: Open a connection
            System.out.println("Connecting to database...");
            try {
              conn = DriverManager.getConnection(DB_URL, USER, PASS);
            } catch (SQLException e) {
              e.printStackTrace();
            }
    
           String insertPreparedSql = "INSERT INTO employee " + "VALUES (?, 'Zara', 'Zara','Zara')";
    
            try {
              pStmt = conn.prepareStatement(insertPreparedSql);
            } catch (SQLException e) {
              e.printStackTrace();
            }
    
            for (int i = 0; i < 100; i++) {
              try {
                pStmt.setInt(1, i*10);
                pStmt.execute();
              } catch (SQLException e) {
                e.printStackTrace();
              }
            }
    
            String selectLimitSql = "SELECT * FROM employee limit ?, ?";
            // select with limit
            try {
              pStmt = conn.prepareStatement(selectLimitSql);
              int pageNo = 0;
              pStmt.setInt(1, pageNo * PAGESIZE);
              pStmt.setInt(2, PAGESIZE);
              ResultSet rs = pStmt.executeQuery();
              while (!rs.wasNull()) {
                while(rs.next()) {
                  System.out.println("id: " + String.valueOf(rs.getInt(1)) + " name: " + rs.getString(2));
                }
    
                pageNo = pageNo + 1;
                pStmt.setInt(1, pageNo * PAGESIZE);
                pStmt.setInt(2, PAGESIZE);
                rs = pStmt.executeQuery();
              }
              rs.close();
            } catch (SQLException e) {
              e.printStackTrace();
            }
          }
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      相关资源
      最近更新 更多