一文說透什么是MySQL的預(yù)編譯
一、什么是MySQL的預(yù)編譯?
通常我們發(fā)送一條SQL語句給MySQL服務(wù)器時,MySQL服務(wù)器每次都需要對這條SQL語句進(jìn)行校驗(yàn)、解析等操作。
但是有很多情況下,我們的一條SQL語句可能需要反復(fù)的執(zhí)行,而SQL語句也只可能傳遞的參數(shù)不一樣,類似于這樣的SQL語句如果每次都需要進(jìn)行校驗(yàn)、解析等操作,未免太過于浪費(fèi)性能了,因此我們提出了SQL語句的預(yù)編譯。
所謂預(yù)編譯就是將一些靈活的參數(shù)值以占位符?的形式給代替掉,我們把參數(shù)值給抽取出來,把SQL語句進(jìn)行模板化。
讓MySQL服務(wù)器執(zhí)行相同的SQL語句時,不需要在校驗(yàn)、解析SQL語句上面花費(fèi)重復(fù)的時間
預(yù)編譯其實(shí)就是來提高我們的查詢速度的,并不是大家心里想的那個"預(yù)編譯"
二、 如何使用預(yù)編譯?
2.1 MySQL預(yù)編譯的語法
準(zhǔn)備數(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ū)');
定義預(yù)編譯SQL語句:
-- 定義一個預(yù)編譯語句 prepare name from statement; prepare statement_1 from 'select * from user where id=?';
設(shè)置參數(shù)值:
set @id=1;
執(zhí)行預(yù)編譯SQL語句:
execute statement_1 using @id;
釋放預(yù)編譯SQL語句:
deallocate prepare statement_1;
三、使用PreparedStatement進(jìn)行預(yù)編譯
3.1 開啟查詢?nèi)罩?/h3>
為了方便測試,我們打開MySQL的查詢?nèi)罩荆?/p>
在MySQL配置文件中的[mysqld]下增加如下配置:
# 是否開啟mysql日志 0:關(guān)閉(默認(rèn)值) 1:開啟 general-log=1 # mysql 日志的存放位置 general_log_file="D:/query.log"
2)重啟MySQL服務(wù)(要以管理員身份運(yùn)行):
net stop mysql net start mysql
3.2 開啟預(yù)編譯功能
PreparedStatement的預(yù)編譯功能默認(rèn)是關(guān)閉的,要讓其生效,必須在JDBC連接的URL設(shè)置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>
我們設(shè)置的是MySQL連接參數(shù),目的是告訴MySQL JDBC的PreparedStatement使用預(yù)編譯功能(5.0.5之后的JDBC驅(qū)動版本需要手動開啟,而之前的默認(rèn)是開啟的)
3.3 cachePrepStmts參數(shù)
當(dāng)使用不同的PreparedStatement對象來執(zhí)行相同的SQL語句時,還是會出現(xiàn)編譯兩次的現(xiàn)象,我們可以開啟"預(yù)編譯緩存",來實(shí)現(xiàn)"一次編譯,到處運(yùn)行"(要是同一個Connection)
開啟預(yù)編譯緩存: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>
開啟預(yù)編譯緩存測試(在url連接上加上cachePrepStmts=true
):
jdbc:mysql://localhost:3306/mybatis?useServerPrepStmts=true&cachePrepStmts=true
四、Statement是否具備預(yù)編譯功能?
Statement不具備預(yù)編譯功能
測試代碼:
@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)到了這里,大家應(yīng)該知道什么是預(yù)編譯了,預(yù)編譯是用來提升SQL語句的響應(yīng)速度的,將一段SQL語句定制成模板,把靈活的參數(shù)作為占位符讓我們傳遞進(jìn)去,達(dá)到多次執(zhí)行相同的SQL語句必須要重復(fù)校驗(yàn)、解析等操作;
2)默認(rèn)的情況下,PreparedStatement是沒有開啟預(yù)編譯的,需要我們在連接的url參數(shù)上指定useServerPrepStmts=true
參數(shù)開啟,并且預(yù)編譯是支持"緩存"的,我們可以通過參數(shù)cachePrepStmts=true
來設(shè)置;
3)statement是不支持預(yù)編譯的,即使設(shè)置了useServerPrepStmts=true
也不管用;
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
mysql中日期的加減 date_add()、date_sub() 函數(shù)及用法小結(jié)
在Mysql中,date_add與date_sub分別是指對于日期的一個加減操作,date_add是指從日期中加上指定的時間間隔,date_sub是指從日期中減去指定的時間間隔,本文通過實(shí)例講解mysql中日期的加減 date_add()、date_sub() 函數(shù)及用法小結(jié),感興趣的朋友一起看看吧2023-11-11Mysql主從三種復(fù)制模式(異步復(fù)制,半同步復(fù)制,組復(fù)制)
這篇文章主要介紹了Mysql主從三種復(fù)制模式(異步復(fù)制,半同步復(fù)制,組復(fù)制),MySQL異步復(fù)制是主從復(fù)制過程中默認(rèn)的復(fù)制模式,下文簡單介紹,感興趣的朋友可以參考一下2022-08-08MySQL之使用WITH子句和臨時表達(dá)式進(jìn)行數(shù)據(jù)分析和篩選方式
這篇文章主要介紹了MySQL之使用WITH子句和臨時表達(dá)式進(jìn)行數(shù)據(jù)分析和篩選方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04MySQL中sleep函數(shù)的特殊現(xiàn)象示例詳解
這篇文章主要給大家介紹了關(guān)于MySQL中sleep函數(shù)特殊現(xiàn)象的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10Linux上通過binlog文件恢復(fù)mysql數(shù)據(jù)庫詳細(xì)步驟
binglog文件是服務(wù)器的二進(jìn)制日志記錄著該數(shù)據(jù)庫的所有增刪改的操作日志,接下來通過本文給大家介紹linux上通過binlog文件恢復(fù)mysql數(shù)據(jù)庫詳細(xì)步驟,非常不錯,需要的朋友參考下2016-08-08MySQL數(shù)據(jù)庫事務(wù)原理及應(yīng)用
MySQL數(shù)據(jù)庫事務(wù)是指一組數(shù)據(jù)庫操作,要么全部執(zhí)行成功,要么全部回滾。事務(wù)可以確保數(shù)據(jù)的一致性和完整性,避免了多個用戶同時對同一數(shù)據(jù)進(jìn)行修改所帶來的問題。MySQL通過事務(wù)日志記錄事務(wù)的操作,支持事務(wù)的回滾和提交等操作2023-04-04一文弄懂MySQL中redo?log與binlog的區(qū)別
在學(xué)習(xí)mysql數(shù)據(jù)庫時,不可避免要去接觸到redo log和binlog,好多人對這兩者的概念分不太清,下面這篇文章主要給大家介紹了關(guān)于MySQL中redo?log與binlog區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-02-02