一文說透什么是MySQL的預編譯
一、什么是MySQL的預編譯?
通常我們發(fā)送一條SQL語句給MySQL服務器時,MySQL服務器每次都需要對這條SQL語句進行校驗、解析等操作。
但是有很多情況下,我們的一條SQL語句可能需要反復的執(zhí)行,而SQL語句也只可能傳遞的參數(shù)不一樣,類似于這樣的SQL語句如果每次都需要進行校驗、解析等操作,未免太過于浪費性能了,因此我們提出了SQL語句的預編譯。
所謂預編譯就是將一些靈活的參數(shù)值以占位符?的形式給代替掉,我們把參數(shù)值給抽取出來,把SQL語句進行模板化。
讓MySQL服務器執(zhí)行相同的SQL語句時,不需要在校驗、解析SQL語句上面花費重復的時間
預編譯其實就是來提高我們的查詢速度的,并不是大家心里想的那個"預編譯"
二、 如何使用預編譯?
2.1 MySQL預編譯的語法
準備數(shù)據(jù):
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', '男', '南昌市西湖區(qū)'); INSERT INTO `user` VALUES (2, '小剛', '2019-03-02 15:09:37', '男', '南昌市東湖區(qū)'); INSERT INTO `user` VALUES (3, '小蘭', '2019-03-04 11:34:34', '女', '南昌市青山湖區(qū)'); INSERT INTO `user` VALUES (4, '小紅', '2019-03-04 12:04:06', '女', '南昌市青云譜區(qū)'); INSERT INTO `user` VALUES (5, '小麗', '2019-03-07 17:37:26', '女', '南昌市紅谷灘區(qū)'); INSERT INTO `user` VALUES (6, '小明', '2019-03-08 11:44:00', '男', '南昌市新建區(qū)'); INSERT INTO `user` VALUES (7, '龍龍', '2019-04-08 11:44:00', '男', '南昌市西湖區(qū)');

定義預編譯SQL語句:
-- 定義一個預編譯語句 prepare name from statement; prepare statement_1 from 'select * from user where id=?';
設置參數(shù)值:
set @id=1;
執(zhí)行預編譯SQL語句:
execute statement_1 using @id;

釋放預編譯SQL語句:
deallocate prepare statement_1;
三、使用PreparedStatement進行預編譯
3.1 開啟查詢?nèi)罩?/h3>
為了方便測試,我們打開MySQL的查詢?nèi)罩荆?/p>
在MySQL配置文件中的[mysqld]下增加如下配置:
# 是否開啟mysql日志 0:關(guān)閉(默認值) 1:開啟 general-log=1 # mysql 日志的存放位置 general_log_file="D:/query.log"

2)重啟MySQL服務(要以管理員身份運行):

net stop mysql net start mysql
3.2 開啟預編譯功能
PreparedStatement的預編譯功能默認是關(guān)閉的,要讓其生效,必須在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);
// 執(zhí)行查詢,獲取結(jié)果集
ResultSet rs = ps.executeQuery();
//遍歷查詢結(jié)果集
while (rs.next()) {
System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
}
rs.close();
ps.close();
}
}查看MySQL的查詢?nèi)罩荆?/p>

我們設置的是MySQL連接參數(shù),目的是告訴MySQL JDBC的PreparedStatement使用預編譯功能(5.0.5之后的JDBC驅(qū)動版本需要手動開啟,而之前的默認是開啟的)
3.3 cachePrepStmts參數(shù)
當使用不同的PreparedStatement對象來執(zhí)行相同的SQL語句時,還是會出現(xiàn)編譯兩次的現(xiàn)象,我們可以開啟"預編譯緩存",來實現(xiàn)"一次編譯,到處運行"(要是同一個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);
// 執(zhí)行查詢,獲取結(jié)果集
ResultSet rs = ps.executeQuery();
//遍歷查詢結(jié)果集
while (rs.next()) {
System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
}
// 關(guān)閉對象連接
rs.close();
ps.close();
ps = connection.prepareStatement(sql);
ps.setInt(1, 1);
// 執(zhí)行查詢,獲取結(jié)果集
rs = ps.executeQuery();
//遍歷查詢結(jié)果集
while (rs.next()) {
System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
}
rs.close();
ps.close();
}查看查詢?nèi)罩荆?/p>

開啟預編譯緩存測試(在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();
// 執(zhí)行查詢,獲取結(jié)果集
ResultSet rs = statement.executeQuery(sql);
//遍歷查詢結(jié)果集
while (rs.next()) {
System.out.println(rs.getObject("id")+"---"+rs.getObject("username"));
}
rs.close();
statement.close();
}查看MySQL查詢?nèi)罩荆?/p>

五、總結(jié)
1)到了這里,大家應該知道什么是預編譯了,預編譯是用來提升SQL語句的響應速度的,將一段SQL語句定制成模板,把靈活的參數(shù)作為占位符讓我們傳遞進去,達到多次執(zhí)行相同的SQL語句必須要重復校驗、解析等操作;
2)默認的情況下,PreparedStatement是沒有開啟預編譯的,需要我們在連接的url參數(shù)上指定useServerPrepStmts=true參數(shù)開啟,并且預編譯是支持"緩存"的,我們可以通過參數(shù)cachePrepStmts=true來設置;
3)statement是不支持預編譯的,即使設置了useServerPrepStmts=true也不管用;
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
mysql中日期的加減 date_add()、date_sub() 函數(shù)及用法小結(jié)
在Mysql中,date_add與date_sub分別是指對于日期的一個加減操作,date_add是指從日期中加上指定的時間間隔,date_sub是指從日期中減去指定的時間間隔,本文通過實例講解mysql中日期的加減 date_add()、date_sub() 函數(shù)及用法小結(jié),感興趣的朋友一起看看吧2023-11-11
MySQL之使用WITH子句和臨時表達式進行數(shù)據(jù)分析和篩選方式
這篇文章主要介紹了MySQL之使用WITH子句和臨時表達式進行數(shù)據(jù)分析和篩選方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04
MySQL中sleep函數(shù)的特殊現(xiàn)象示例詳解
這篇文章主要給大家介紹了關(guān)于MySQL中sleep函數(shù)特殊現(xiàn)象的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者使用MySQL具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2019-10-10
Linux上通過binlog文件恢復mysql數(shù)據(jù)庫詳細步驟
binglog文件是服務器的二進制日志記錄著該數(shù)據(jù)庫的所有增刪改的操作日志,接下來通過本文給大家介紹linux上通過binlog文件恢復mysql數(shù)據(jù)庫詳細步驟,非常不錯,需要的朋友參考下2016-08-08
一文弄懂MySQL中redo?log與binlog的區(qū)別
在學習mysql數(shù)據(jù)庫時,不可避免要去接觸到redo log和binlog,好多人對這兩者的概念分不太清,下面這篇文章主要給大家介紹了關(guān)于MySQL中redo?log與binlog區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-02-02

