一文说透什么是MySQL的预编译

 更新时间:2022年11月15日 11:35:02   作者:緑水長流*z  
这篇文章主要介绍了一文说透什么是MySQL的预编译,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

一、什么是MySQL的预编译?

通常我们发送一条SQL语句给MySQL服务器时,MySQL服务器每次都需要对这条SQL语句进行校验、解析等操作。

但是有很多情况下,我们的一条SQL语句可能需要反复的执行,而SQL语句也只可能传递的参数不一样,类似于这样的SQL语句如果每次都需要进行校验、解析等操作,未免太过于浪费性能了,因此我们提出了SQL语句的预编译。

所谓预编译就是将一些灵活的参数值以占位符?的形式给代替掉,我们把参数值给抽取出来,把SQL语句进行模板化

让MySQL服务器执行相同的SQL语句时,不需要在校验、解析SQL语句上面花费重复的时间

预编译其实就是来提高我们的查询速度的,并不是大家心里想的那个"预编译"

二、 如何使用预编译?

2.1 MySQL预编译的语法

准备数据:

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名称',
  `birthday` datetime(0) NULL DEFAULT NULL COMMENT '生日',
  `sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',
  `address` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '小龙', '2019-02-27 17:47:08', '男', '南昌市西湖区');
INSERT INTO `user` VALUES (2, '小刚', '2019-03-02 15:09:37', '男', '南昌市东湖区');
INSERT INTO `user` VALUES (3, '小兰', '2019-03-04 11:34:34', '女', '南昌市青山湖区');
INSERT INTO `user` VALUES (4, '小红', '2019-03-04 12:04:06', '女', '南昌市青云谱区');
INSERT INTO `user` VALUES (5, '小丽', '2019-03-07 17:37:26', '女', '南昌市红谷滩区');
INSERT INTO `user` VALUES (6, '小明', '2019-03-08 11:44:00', '男', '南昌市新建区');
INSERT INTO `user` VALUES (7, '龙龙', '2019-04-08 11:44:00', '男', '南昌市西湖区');

定义预编译SQL语句:

-- 定义一个预编译语句
prepare name from statement; 

prepare statement_1 from 'select * from user where id=?';

设置参数值:

set @id=1;

执行预编译SQL语句:

execute statement_1 using @id;

释放预编译SQL语句:

deallocate prepare statement_1;

三、使用PreparedStatement进行预编译

3.1 开启查询日志

为了方便测试,我们打开MySQL的查询日志:

在MySQL配置文件中的[mysqld]下增加如下配置:

# 是否开启mysql日志  0:关闭(默认值) 1:开启
general-log=1

# mysql 日志的存放位置
general_log_file="D:/query.log"

2)重启MySQL服务(要以管理员身份运行):

net stop mysql

net start mysql

3.2 开启预编译功能

PreparedStatement的预编译功能默认是关闭的,要让其生效,必须在JDBC连接的URL设置useServerPrepStmts=true,让其打开。

如下所示:

jdbc:mysql://localhost:3306/mybatis?&useServerPrepStmts=true

测试代码:

package com.lscl.test;
import org.junit.Test;
import java.sql.*;

public class Demo01 {
    @Test
    public void test1() throws Exception {

        // 获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useServerPrepStmts=true", "root", "admin");

        String sql = "select * from user where id = ?";

        PreparedStatement ps = connection.prepareStatement(sql);

        ps.setInt(1, 1);

        // 执行查询,获取结果集
        ResultSet rs = ps.executeQuery();

        //遍历查询结果集
        while (rs.next()) {
            System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
        }
        rs.close();
        ps.close();

    }
}

查看MySQL的查询日志:

我们设置的是MySQL连接参数,目的是告诉MySQL JDBC的PreparedStatement使用预编译功能(5.0.5之后的JDBC驱动版本需要手动开启,而之前的默认是开启的)

3.3 cachePrepStmts参数

当使用不同的PreparedStatement对象来执行相同的SQL语句时,还是会出现编译两次的现象,我们可以开启"预编译缓存",来实现"一次编译,到处运行"(要是同一个Connection)

开启预编译缓存:cachePrepStmts=true;

url连接:

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

测试代码(没有开启缓存):

@Test
public void test1() throws Exception {

    // 获取连接
//        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useServerPrepStmts=true&cachePrepStmts=true", "root", "admin");
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useServerPrepStmts=true", "root", "admin");

    String sql = "select * from user where id = ?";

    PreparedStatement ps = connection.prepareStatement(sql);

    ps.setInt(1, 1);

    // 执行查询,获取结果集
    ResultSet rs = ps.executeQuery();

    //遍历查询结果集
    while (rs.next()) {
        System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
    }

    // 关闭对象连接
    rs.close();
    ps.close();

    ps = connection.prepareStatement(sql);

    ps.setInt(1, 1);

    // 执行查询,获取结果集
    rs = ps.executeQuery();

    //遍历查询结果集
    while (rs.next()) {
        System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
    }

    rs.close();
    ps.close();

}

查看查询日志:

开启预编译缓存测试(在url连接上加上cachePrepStmts=true):

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

四、Statement是否具备预编译功能?

Statement不具备预编译功能

测试代码:

@Test
public void test2() throws Exception {

    // 获取连接
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?useServerPrepStmts=true&cachePrepStmts=true", "root", "admin");

    String sql = "select * from user where id = 1";

    Statement statement = connection.createStatement();

    // 执行查询,获取结果集
    ResultSet rs = statement.executeQuery(sql);

    //遍历查询结果集
    while (rs.next()) {
        System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
    }

    rs.close();
    statement.close();
}

查看MySQL查询日志:

五、总结

1)到了这里,大家应该知道什么是预编译了,预编译是用来提升SQL语句的响应速度的,将一段SQL语句定制成模板,把灵活的参数作为占位符让我们传递进去,达到多次执行相同的SQL语句必须要重复校验、解析等操作;

2)默认的情况下,PreparedStatement是没有开启预编译的,需要我们在连接的url参数上指定useServerPrepStmts=true参数开启,并且预编译是支持"缓存"的,我们可以通过参数cachePrepStmts=true来设置;

3)statement是不支持预编译的,即使设置了useServerPrepStmts=true也不管用;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 简述MySQL 正则表达式

    简述MySQL 正则表达式

    大家都知道MySQL可以通过 LIKE ...% 来进行模糊匹配,MySQL 同样也支持其他正则表达式的匹配, MySQL中使用 REGEXP 操作符来进行正则表达式匹配。对mysql正则表达式知识感兴趣的朋友一起看看吧
    2016-11-11
  • mysql 日期和时间格式转换实现语句

    mysql 日期和时间格式转换实现语句

    对于每个类型拥有的值范围以及并且指定日期何时间值的有效格式的描述见7.3.6 日期和时间类型。
    2009-10-10
  • mysql出现“Incorrect key file for table”处理方法

    mysql出现“Incorrect key file for table”处理方法

    今天在恢复一个客户数据的时候。发现了一贯问题。有多个表损坏了。因为都是直接把表复制进去的。然后就出现了这个问题问题
    2013-07-07
  • Ubuntu下取消MySQL数据库本机绑定限制方法

    Ubuntu下取消MySQL数据库本机绑定限制方法

    在Ubuntu系统中,添加了MySQL账户,赋予了数据库完全操作权限,并且允许数据库从外部链接 但是,还是无法远程访问MySQL数据库
    2013-06-06
  • MySQL中索引的优化的示例详解

    MySQL中索引的优化的示例详解

    索引是数据库优化最常用也是最重要的手段之一,通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。本文主要来讲讲索引优化的方法,希望对大家有所帮助
    2023-02-02
  • MySQL 8忘记密码的最佳处理方式浅析

    MySQL 8忘记密码的最佳处理方式浅析

    这篇文章主要给大家介绍了关于MySQL 8忘记密码的处理方式,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02
  • MySQL修改配置 区分大小写

    MySQL修改配置 区分大小写

    修改MySql Server安装目录下的 my.ini 文件,在mysqld节下加入下面一行 set-variable=lower_case_table_names=0 (0:大小写敏感;1:大小写不敏感)最后重启一下MySql服务即可。
    2010-12-12
  • mysql登录警告问题的解决方法

    mysql登录警告问题的解决方法

    这篇文章主要为大家详细介绍了mysql登录警告问题的解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • MySQL中设置NULL和空白字符串的问题及解决

    MySQL中设置NULL和空白字符串的问题及解决

    这篇文章主要介绍了MySQL中设置NULL和空白字符串的问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • MySQL运行在docker容器性能损失解析

    MySQL运行在docker容器性能损失解析

    这篇文章主要为大家介绍了MySQL运行在docker容器中的性能损失解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11

最新评论