1. 程式人生 > SQL入門教學 >34 SQL Prepare

34 SQL Prepare

1. 定義

解釋:SQL預處理(Prepare),是一種特殊的 SQL 處理方式;預處理不會直接執行 SQL 語句,而是先將 SQL 語句編譯,生成執行計劃,然後通過 Execute 命令攜帶 SQL 引數執行 SQL 語句。

2. 前言

本小節,我們將一起學習 SQL Prepare

在生產環境中,我們會多次執行一條 SQL 語句,如果每次都處理該 SQL 語句,生成執行計劃,必然會浪費一定的時間。SQL 預處理是一種特殊的 SQL 處理方式,它會預先根據 SQL 語句模板來生成對應的執行計劃,而後只需攜帶 SQL 引數便能直接執行,提升了 SQL 執行的效能,是一種典型的空間換時間的演算法優化。

本小節測試資料如下,請先在資料庫中執行:

DROP TABLE IF EXISTS imooc_user;
CREATE TABLE imooc_user
(
  id int PRIMARY KEY,
  username varchar(20),
  age int
);
INSERT INTO imooc_user(id,username,age)
VALUES (1,'peter',18),(2,'pedro',24),(3,'jerry',22),(4,'mike',18),(5,'tom',20);

3. 語法

不同資料庫對於 Prepare 的支援差異較大,本小節我們將分別介紹 MySQL 和 PostgreSQL 的預處理語法及案例。

3.1 MySQL

MySQL 預處理是一組 SQL 操作的集合,它沒有固定的語法格式,但多數情況下會按照如下 3 個步驟使用。

  1. 使用PREPARE指令預定義 SQL 語句模板;
  2. 使用SET指令定義 SQL 引數;
  3. 使用EXECUTE指令攜帶引數執行 SQL 模板。

我們以通過id查詢使用者為例來詳細說明 Prepare 的使用。

1、按照上述的步驟,我們應先使用 Prepare 來預定義通過“id查詢使用者”的 SQL 模板,如下:

PREPARE finduserbyidstm FROM 'SELECT * FROM imooc_user WHERE id = ?';

Prepare 指令後面便是 SQL 語句模板的名稱,此處我們將模板的名稱定義為finduserbyidstm

。定義名稱後,應該指定該名稱來源的 SQL 模板,即 FROM 指令後的 SQL 語句就是 finduserbyidstm 對應的 SQL 語句模板。

注意: 既然是模板,那麼必然會有引數的佔位符,如 MySQL 的佔位符是 ?,而 PostgreSQL 的佔位符則不同,它會根據引數的序列來依次定義,如第一個引數的佔位符是$1,第二個引數的佔位符則是$2

2、定義好預處理 SQL 模板後,我們還需定義 SQL 引數,如下:

SET @id = 1;

SQL 定義變數,需以@來開頭,如 @id,表示變數名為 id,變數值為 1。

3、通過 EXECUTE 攜帶引數來真正地執行 SQL:

EXECUTE finduserbyidstm USING @id;

EXECUTE 後面是已經定義好的模板名稱 finduserbyidstm,且使用 USING 指令來指定使用到的變數引數。

執行成功後,結果如下:

+----+----------+-----+
| id | username | age |
+----+----------+-----+
| 1  | peter    | 18  |
+----+----------+-----+

3.2 PostgreSQL

PostgreSQL 預處理也是一組 SQL 操作的集合,不過它只需要兩個步驟即可完成。

  1. 使用PREPARE指令預定義 SQL 語句模板;
  2. 使用EXECUTE指令攜帶引數執行 SQL 模板。

我們還是以通過id查詢使用者為例來詳細說明 Prepare 的使用。

1、 使用 PREPARE 來預定義模板:

PREPARE finduserbyidstm(int) AS SELECT * FROM imooc_user WHERE id = $1;

PostgreSQL 的模板定義更為嚴格,不僅需要指定模板名稱,還需指定引數型別,如 finduserbyidstm 模板共有一個引數,且型別為 int。模板名稱與語句之間不再使用 FROM 連線,而是使用AS,且後面直接接上 SQL 語句,不需要 ‘’ 來包裹成字串。佔位符為$1,若有第二個佔位符,則應該為$2

2、 使用 EXECUTE 執行:

EXECUTE finduserbyidstm(1);

PostgreSQL 執行較為簡單,不要定義變數再使用,直接在模板名稱中指定引數值即可,即 1。

執行後的結果如下:

 id | username | age
----+----------+-----
  1 | peter    |  18

4. 實踐

預處理的語法和步驟比較複雜,接下來以一個例項來鞏固一下。

4.1 例1 預處理插入使用者

請書寫 SQL 語句,使用預處理的方式插入一個名為lucy的使用者,該使用者年齡為17

分析:

按照上面流程和語法,依次完成即可。

語句:

整理可得語句如下:

PREPARE insertuserstm FROM 'INSERT INTO imooc_user(id,username,age) VALUES(?,?,?)';
SET @id = 6,@username='lucy',@age=17;
EXECUTE insertuserstm USING @id,@username,@age;

結果如下:

+----+----------+-----+
| id | username | age |
+----+----------+-----+
| 6  | lucy     | 17  |
+----+----------+-----+

如果使用 PostgreSQL,則語句如下:

PREPARE insertuserstm(int,varchar,int) AS INSERT INTO imooc_user(id,username,age) VALUES($1,$2,$3);
EXECUTE insertuserstm(6,'lucy',17);

5. 小結

  • Prepare 的使用其實十分廣泛,絕大多數 ORM 框架都有 API 支援。
  • Prepare 既可以提升 SQL 執行效能,還能防止 SQL 注入引發的安全問題。
  • Prepare 雖然在每個資料庫中的語法差異很大,但是一般情況下我們都不會手寫 SQL,而是使用 ORM 框架來做。