什么是MySQL的预编译?

标签: MySQL  数据库  mysql  mybatis  jdbc  java

一、什么是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也不管用;


References:

https://www.iteye.com/blog/cs-css-1847772

https://blog.csdn.net/Marvel__Dead/article/details/69486947

版权声明:本文为Bb15070047748原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Bb15070047748/article/details/107266400

智能推荐

mysql几个参数(编码,预编译,批处理)

背景  这两天在做数据同步项目的联调,测试过程中发现针对mysql的一些使用上存在一些问题,比如batch不起效果,编码问题,预编译失效等等。 这里总结一下,做一下记录,希望对遇到类似问题的有所帮助 内容 编码问题 官方文档: http://dev.mysql.com/doc/refman/4.1/en/connector-j-reference-charsets.html 网...

mysql几个参数(编码,预编译,批处理)

背景  这两天在做数据同步项目的联调,测试过程中发现针对mysql的一些使用上存在一些问题,比如batch不起效果,编码问题,预编译失效等等。 这里总结一下,做一下记录,希望对遇到类似问题的有所帮助 内容 编码问题 官方文档: http://dev.mysql.com/doc/refman/4.1/en/connector-j-reference-charsets.html 网...

Mysql预编译动态拼接表名查询

1.实现目标,现在对deal_runnning表进行按年月分表,需要动态拼接表名查询 2.需要执行此sql .表名要动态拼接,目标sql如下,使用concat连接表名无效. 3.解决办法,使用mysql的预编译动态sql处理  ...

网络编程

主要内容 软件架构CS/BS 网络通信三要素 TCP通信 Socket套接字 ServerSocket 教学目标 能够辨别UDP和TCP协议特点 能够说出TCP协议下两个常用类名称 能够编写TCP协议下字符串数据传输程序 能够理解TCP协议下文件上传案例 能够理解TCP协议下BS案例 第一章 网络编程概述 1.1 软件结构 C/S结构 :全称为Client/Server结构,是指客户端和服务器结构...

JavaScript实现软件光栅化渲染器01-如何画点

项目代码:https://github.com/foupwang/JavaScript3DRenderer 开发环境:VSCode+Chrome浏览器 参考:《Windows游戏编程大师技巧》(第2版) /《3D游戏编程大师技巧》(André LaMothe) QQ交流群:1148938167(欢迎加入探讨图形渲染技术) 整个项目跟平台相关的,只需要一个类似DrawPixel的绘制像...

猜你喜欢

android基础之(动态权限申请)

https://blog.csdn.net/yushuangping/article/details/83758957 背景:     1: android权限的申请,可以在清单文件声明和注册,也可以通过 java 文件动态的注册    2: 在Android6.0之前只需在AndroidManifest.xml文件写明权限即可。但是在A...

C语言按下列形式使用循环生成一个十阶的矩阵A(下三角)到二维数组中,再输出。

题目 按下列形式使用循环生成一个十阶的矩阵A(下三角)到二维数组中,再输出。 代码 运行结果...

脚本尝试mac电脑自动切换公司wifi

公司内部网络,每次需要登录。需要几步,选择WIFI 弹出登录页,输入用户密码才可登录成功。 因此,有一个想法利用脚本进行wifi自动登录。 提供一些思路,做出来体验不好,凑合能用,路过大神予以改进。 实现情况如下 1.需要获取登录url。就是弹出界面需要登录的url 利用抓包软件,可以做此事。mac中软件charles 主要是抓取登录时候的curl。如此可以通过curl命令直接进行登录。 2.自动...

反素数入门 zoj 2562 and codefore

学习资料来源传送们 反素数的定义:对于任何正整数,其约数个数记为,例如,如果某个正整数满足:对任意的正整             数,都有,那么称为反素数 定义理解:素数的约数只有两个 1  和  本身,而反素数的约数是尽可能多,比这个数小到正数的约数都要多 在ACM竞...

Scala语言基础(三)练习

(1)打印九九乘法表 简写 (二)worldCount实现 1.推演过程 2.综合起来 3.两个简化点 a. 其中,array.map(x => x.split(" “)).flatten效果和array.flatMap(x => x.split(” "))一致: b. 通过mapValues方法,直接作用于Map的value值,只改变val...