JDBC mysql不支持PreparedStatement中的LIMIT占位符?
Posted
技术标签:
【中文标题】JDBC mysql不支持PreparedStatement中的LIMIT占位符?【英文标题】:JDBC mysql does not support placeholder of LIMIT in PreparedStatement? 【发布时间】: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 【参考方案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();
【讨论】:
以上是关于JDBC mysql不支持PreparedStatement中的LIMIT占位符?的主要内容,如果未能解决你的问题,请参考以下文章
JDBC mysql不支持PreparedStatement中的LIMIT占位符?