MySQL的预编译功能

MySQL的预编译功能

预编译的好处

大家平时都使用过JDBC中的PreparedStatement接口,它有预编译功能。什么是预编译功能呢?它有什么好处呢?

当客户发送一条SQL语句给服务器后,服务器总是需要校验SQL语句的语法格式是否正确,然后把SQL语句编译成可执行的函数,最后才是执行SQL语句。其中校验语法,和编译所花的时间可能比执行SQL语句花的时间还要多。

如果我们需要执行多次insert语句,但只是每次插入的值不同,MySQL服务器也是需要每次都去校验SQL语句的语法格式,以及编译,这就浪费了太多的时间。如果使用预编译功能,那么只对SQL语句进行一次语法校验和编译,所以效率要高。

MySQL执行预编译

MySQL执行预编译分为如三步:

l 执行预编译语句,例如:prepare myfun from ‘select * from t_book where bid=?‘

l 设置变量,例如:set @str=‘b1‘

l 执行语句,例如:execute myfun using @str

如果需要再次执行myfun,那么就不再需要第一步,即不需要再编译语句了:

l 设置变量,例如:set @str=‘b2‘

l 执行语句,例如:execute myfun using @str

通过查看MySQL日志可以看到执行的过程:

使用Statement执行预编译

使用Statement执行预编译就是把上面的SQL语句执行一次。


Connection con = JdbcUtils.getConnection();

Statement stmt = con.createStatement();

stmt.executeUpdate("prepare myfun from ‘select * from t_book where bid=?‘");

stmt.executeUpdate("set @str=‘b1‘");

ResultSet rs = stmt.executeQuery("execute myfun using @str");

while(rs.next()) {

System.out.print(rs.getString(1) + ", ");

System.out.print(rs.getString(2) + ", ");

System.out.print(rs.getString(3) + ", ");

System.out.println(rs.getString(4));

}

stmt.executeUpdate("set @str=‘b2‘");

rs = stmt.executeQuery("execute myfun using @str");

while(rs.next()) {

System.out.print(rs.getString(1) + ", ");

System.out.print(rs.getString(2) + ", ");

System.out.print(rs.getString(3) + ", ");

System.out.println(rs.getString(4));

}

rs.close();

stmt.close();

con.close();

useServerPrepStmts参数

默认使用PreparedStatement是不能执行预编译的,这需要在url中给出useServerPrepStmts=true参数(MySQL Server 4.1之前的版本是不支持预编译的,而Connector/J在5.0.5以后的版本,默认是没有开启预编译功能的)。

例如:jdbc:mysql://localhost:3306/test?useServerPrepStmts=true

  这样才能保证mysql驱动会先把SQL语句发送给服务器进行预编译,然后在执行executeQuery()时只是把参数发送给服务器。


Connection con = JdbcUtils.getConnection();

String sql = "select * from t_book where bid=?";

PreparedStatement pstmt = con.prepareStatement(sql);

pstmt.setString(1, "b1");

ResultSet rs = pstmt.executeQuery();

while(rs.next()) {

System.out.print(rs.getString(1) + ", ");

System.out.print(rs.getString(2) + ", ");

System.out.print(rs.getString(3) + ", ");

System.out.println(rs.getString(4));

}

pstmt.setString(1, "b2");

rs = pstmt.executeQuery();

while(rs.next()) {

System.out.print(rs.getString(1) + ", ");

System.out.print(rs.getString(2) + ", ");

System.out.print(rs.getString(3) + ", ");

System.out.println(rs.getString(4));

}

rs.close();

pstmt.close();

con.close();

cachePrepStmts参数

当使用不同的PreparedStatement对象来执行相同的SQL语句时,还是会出现编译两次的现象,这是因为驱动没有缓存编译后的函数key,导致二次编译。如果希望缓存编译后函数的key,那么就要设置cachePrepStmts参数为true。例如:

jdbc:mysql://localhost:3306/test?useServerPrepStmts=true&cachePrepStmts=true


Connection con = JdbcUtils.getConnection();

String sql = "select * from t_book where bid=?";

PreparedStatement pstmt = con.prepareStatement(sql);

pstmt.setString(1, "b1");

ResultSet rs = pstmt.executeQuery();

while(rs.next()) {

System.out.print(rs.getString(1) + ", ");

System.out.print(rs.getString(2) + ", ");

System.out.print(rs.getString(3) + ", ");

System.out.println(rs.getString(4));

}

pstmt = con.prepareStatement(sql);

pstmt.setString(1, "b2");

rs = pstmt.executeQuery();

while(rs.next()) {

System.out.print(rs.getString(1) + ", ");

System.out.print(rs.getString(2) + ", ");

System.out.print(rs.getString(3) + ", ");

System.out.println(rs.getString(4));

}

rs.close();

pstmt.close();

con.close();

打开批处理

MySQL的批处理也需要通过参数来打开:rewriteBatchedStatements=true

url=jdbc:mysql://localhost:3306/mydb3?rewriteBatchedStatements=true

其它配置项:

#mysql
#url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSize=50&prepStmtCacheSqlLimit=300
#driverClassName=com.mysql.jdbc.Driver

#mssql
#driverClassName=com.microsoft.jdbc.sqlserver.SQLServerDriver
#url=jdbc:sqlserver://127.0.0.1:1433;DatabaseName=mydb

#mssql jtds
#driverClassName=net.sourceforge.jtds.jdbc.Driver
#url=jdbc:jtds:sqlserver://127.0.0.1:1433;DatabaseName=mydb

#orcale
#driverClassName=oracle.jdbc.driver.OracleDriver
#url=jdbc:oracle:thin:@localhost:1521:mydb

#access
#driverClassName=sun.jdbc.odbc.JdbcOdbcDriver
#url=jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=mdb\\mydb.mdb

原文地址:https://www.cnblogs.com/appium/p/10182969.html

时间: 2024-10-29 19:06:21

MySQL的预编译功能的相关文章

Mysql的预编译和批处理

MySQL的预编译功能 预编译的好处 大家平时都使用过JDBC中的PreparedStatement接口,它有预编译功能.什么是预编译功能呢?它有什么好处呢? 当客户发送一条SQL语句给服务器后,服务器总是需要校验SQL语句的语法格式是否正确,然后把SQL语句编译成可执行的函数,最后才是执行SQL语句.其中校验语法,和编译所花的时间可能比执行SQL语句花的时间还要多. 如果我们需要执行多次insert语句,但只是每次插入的值不同,MySQL服务器也是需要每次都去校验SQL语句的语法格式,以及编译

从Mybatis中#和$的区别到SQL预编译

#和$的区别 Mybatis中参数传递可以通过#和$设置.它们的区别是什么呢? # Mybatis在解析SQL语句时,sql语句中的参数会被预编译为占位符问号? $ Mybatis在解析SQL语句时,SQL语句中的参数会被当做字符串拼接SQL. 使用#能够防止SQL注入攻击. 那么什么是预编译? 什么是预编译 通常,一条sql在db接收到最终执行完毕返回需要经历三个阶段: 词法和语义解析 优化sql语句,制定执行计划 执行并返回结果 但是如果同样一条SQL,如果只是参数值变了,不需要每次都语法语

mybatis深入理解之 # 与 $ 区别以及 sql 预编译

mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = "ruhua"; 上述 sql 中,我们希望 name 后的参数 "ruhua" 是动态可变的,即不同的时刻根据不同的姓名来查询用户.在 sqlMap 的 xml 文件中使用如下的 sql 可以实现动态传递参数 name: select * from user whe

mybatis深入理解(一)之 # 与 $ 区别以及 sql 预编译

mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = "ruhua"; 上述 sql 中,我们希望 name 后的参数 "ruhua" 是动态可变的,即不同的时刻根据不同的姓名来查询用户.在 sqlMap 的 xml 文件中使用如下的 sql 可以实现动态传递参数 name: select * from user whe

SQL攻击-预编译--缓存

PreparedStatement l 它是Statement接口的子接口: l 强大之处: 防SQL攻击: 提高代码的可读性.可维护性: 提高效率! l 学习PreparedStatement的用法: 如何得到PreparedStatement对象: ¨ 给出SQL模板! ¨ 调用Connection的PreparedStatement prepareStatement(String sql模板): ¨ 调用pstmt的setXxx()系列方法sql模板中的?赋值! ¨ 调用pstmt的exe

C预编译, 预处理, C/C++头文件, 编译控制,

在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征.依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的. 其格式一般为: #Pragma Para 其中Para 为参数,下面来看一些常用的参数. (1)message 参数. Message 参数是我最喜欢的一个参数,它能够在编译信息输出窗口中输

mybatis以及预编译如何防止SQL注入

SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者).[摘自] SQL injection - Wikipedia SQL注入,大家都不陌生,是一种常见的攻击方式.攻击者在界面的表单信息或URL上输入一些奇怪的SQL片段(例如“or ‘1’=’1’”这样的语句),有可能入侵参数检验不足的应用程序.所以,在我们的应用中需要做一些工作,来防备这样的攻击方式.在一些安全性要求很高的应用中(比如银行软件),经常使用将SQL语句

测试mysql的sql语句预编译效果

玩Oracle的都比较关注shared pool,特别是library cache,在使用了绑定变量(预编译sql)之后确实能得到很大的性能提升.现在在转Mysql之后特别是innodb很多东西都还能和Oracle对得上号的,就像innodb_buffer_pool_size类似于Oracle的database buffer cache,innodb_log_buffer_size类似于redo log buffer,但是innodb_additional_mem_pool_size仅仅类似于s

mysql预编译处理(mysqli、PDO)

DML语句预编译: MysqLi: <?php $mysqli = new mysqli("localhost","root","root","dbname"); $mysqli->query("set names utf8"); $sql = 'insert into user(id,name,age,email) values (?,?,?,?)'; $mysqli_stmt = $mysq