简体   繁体   中英

JDBC mysql does not support placeholder of LIMIT in PreparedStatement?

I used mysql-connector-java-5.1.38 to operate mysql-community-5.7.10.0 on Windows 10 64-bit.

I try to bind value in limit for pagination

"SELECT * FROM employee LIMIT ?, ?"

However the result shows:

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)

However, I tried sql in navicat directly but could get the correct answer:

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;

Here is my entire code:

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

}

Your problem is not about the syntax or MySQL support for LIMIT since it's supported. The problem is about the way you are executing the PreparedStatement .

When using PreparedStatement you may not use the executeQuery(String sql) , because you've prepared the SQL string formerly for the execution, and no need to pass it again in the executeQuery() method. So do this

ResultSet rs = pStmt.executeQuery();

instead of

ResultSet rs = pStmt.executeQuery(selectLimitSql);

With passing again the selectLimitSql (like above line), you are ignoring the following lines:

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

and it is like executing your primitive pure sql which contains '?, ?' place holders and you get that exception.

You do not need to pass the query string. Do this

 ResultSet rs = pStmt.executeQuery();

instead of

ResultSet rs = pStmt.executeQuery(selectLimitSql);

Also, remove the following lines as pagination is taken care of limit in query itself.

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

Following code works:

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

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM