Mysql的预编译和批处理

MySQL的预编译功能

预编译的好处

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

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

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

?

MySQL执行预编译

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

  • 执行预编译语句,例如:prepare myfun from ‘select * from t_book where bid=?‘
  • 设置变量,例如:set @str=‘b1‘
  • 执行语句,例如:execute myfun using @str

?

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

  • 设置变量,例如:set @str=‘b2‘
  • 执行语句,例如: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

?

?

时间: 2024-12-13 08:05:27

Mysql的预编译和批处理的相关文章

MySQL的预编译功能

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

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

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

关于mysql使用prepare关键字预编译语句后是否使用deallocate的区别

下图是mysql数据库中某一数据库,里面有一张user表. 1.新建查询之后,下图展示的使用prepare预编译查询结果(注意:使用了DEALLOCATE关键字删除预编译语句) 2.再次运行刚才的预编译语句aa, 结果出现错误.原因是:之前使用deallocate已经删除了预编译语句. 3.这一次不使用deallocate关键字删除预编译语句. 再一次调用已经预编译过的aa语句. 这一次仍然可以使用该语句. 4.使用deallocate删除该语句. 再次运行已删除语句. 结果再次报错.说明dea

PHP中对mysql预编译查询语句的一个封装

原文地址:http://chen-shan.net/?p=474 为了防止sql注入,我们都使用过mysqli这个类,但是每次都需要绑定参数,绑定结果等,比较麻烦,所以可以把这些重复的语句封装成一个函数. 一.封装前. 传统的一个预编译方式的”select”查询代码: $id = "1"; $name = "test_name"; $db_obj = new mysqli("localhost", "db_user", &qu

mysql sp 练习游标和预编译

create procedure Jack_count_cur_dual() BEGIN DECLARE tb_name VARCHAR(50); DECLARE done int DEFAULT 0; DECLARE mycur CURSOR for SELECT table_name FROM tt_countrows; DECLARE CONTINUE HANDLER FOR NOT FOUND set done = 1; DROP TABLE IF EXISTS tt_countrows