时间:2021-07-01 10:21:17 帮助过:22人阅读
jdbc测试mysql数据库sql预解析(绑定变量) 用习惯了oracle,学习mysql,想测试一下mysql绑定变量的效果。以前看网上介绍大部份都说mysql没有sql共享池的概念,所以也不存在sql预解析或绑定变量的说法。 今天测试了一下(通过网络抓包、查看服务器端sql日志及
jdbc测试mysql数据库sql预解析(绑定变量)
- PreparedStatement pstmt = conn.prepareStatement("select * from t1 where c1=?");
- pstmt.setString(1, "abc");
- pstmt.execute();
实际上不会有预解析的过程,而是经过简单的拼接,把如下SQL发送给服务器
要实现预解析的效果,我们必须设置jdbc Connection的参数useServerPrepStmts=true,再使用PreparedStatement后就OK了,创建PreparedStatement时客户端先把"select * from t1 where c1=?"发送到服务器端预解析,execute时只是把变量传送到服务器执行。
- select * from t1 where c1='abc'
- mysql> show status like 'Prepared_stmt_count';
- +---------------------+-------+
- | Variable_name | Value |
- +---------------------+-------+
- | Prepared_stmt_count | 1 |
- +---------------------+-------+
- 1 row in set
当有PreparedStatement缓存时,预解析的SQL文本缓存在服务器端,但是并不会像oracle一样缓存执行计划,所以每次execute时都需要解析SQL和生成执行计划,因此只是减少了每次execute传输SQL的文本大小,性能差别不大。
注:如果SQL语法错误,那么服务器端预解析会出错,但jdbc收到预解析出错的信息后并不提示出错,而是将取消本条语句预解析的状态,execute时直接把SQL接装发送给服务器,mysql jdbc在PreparedStatement构造函数中代码如下,其中返回ServerPreparedStatement类表示使用了绑定变量,返回PreparedStatement表示未使用绑定变量:
经过上面分析,个人认为不需要打开SQL预解析的效果,PreparedStatement对象还是尽量使用,因为虽然不能提升性能,但可以避免SQL注入安全问题 。
- try {
- pStmt = ServerPreparedStatement.getInstance(getLoadBalanceSafeProxy(), nativeSql,
- this.database, resultSetType, resultSetConcurrency);
- pStmt.setResultSetType(resultSetType);
- pStmt.setResultSetConcurrency(resultSetConcurrency);
- } catch (SQLException sqlEx) {
- // Punt, if necessary
- if (getEmulateUnsupportedPstmts()) {
- pStmt = (PreparedStatement) clientPrepareStatement(nativeSql, resultSetType, resultSetConcurrency, false);
- } else {
- throw sqlEx;
- }
- }