1. 程式人生 > SQL入門教學 >33 SQL 鎖

33 SQL 鎖

1. 定義

解釋:一把對應一扇門,獲得鎖的可以進門,否則只能在門外等待。

2. 前言

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

在一些併發場景中,會涉及到一些資料競爭問題。如 A、B 二人同時要修改同一條記錄,如果二人可以對其同時修改,那麼很大的概率上,資料會起衝突,為了保證資料的安全性和正確性,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. 鎖的分類

鎖的種類非常多,專業名詞數不勝數,我們無需將其所有都記住,在本小節我們只瞭解其常用且提及最廣的部分。

從鎖的粒度上,我們可以將其大致的分為如下幾類:

名稱 描述 說明
庫鎖 鎖定某個資料庫 粒度最大,若非特殊情況(資料庫備份),切勿使用。
表鎖 鎖定某張資料表 粒度也比較大,直接涉及一張表,若非特殊情況,也勿使用。
頁鎖 鎖定某張資料頁 SQL Server 特有的鎖,會鎖定資料頁,資料表中的資料是按頁組織的。
行鎖 鎖定某一行記錄 粒度最小,只鎖定一條記錄,推薦使用。

從資料庫系統管理角度來看,可以把鎖分為如下兩大類:

名稱 描述 說明
共享鎖 其他人可以讀取,但不能修改 也被稱為讀鎖
排他鎖 其他人不能讀取,也不能修改 也被稱為寫鎖

鎖的種類還有很多,實現方式也多姿多彩,如果你感興趣,可以查閱一下相關的資料。

我們分別從粒度和管理兩個角度上對鎖進行了分類。

在粒度上,不同資料庫,甚至不同引擎對鎖的粒度支援都是不同的,如 MySQL 的 InnoDB 引擎支援行鎖、表鎖和庫鎖,而 MyISAM 引擎只能支援到表鎖。對於頁鎖,只有 SQL Server 支援,而不同資料庫也有類似間隙鎖的實現,它的功能與頁鎖差不多。

在管理上,鎖根據資料是否共享來分類,對於讀多寫少的場景,共享鎖幾乎是併發的標配,而一旦涉及資料修改,鎖就必須獨佔了。

4. 實踐

下面,我們以幾個例子來熟悉一下鎖的使用。

4.1 例1、鎖住 imooc_user 表

在 SQL 中,你可以通過如下語句鎖住某一張表:

LOCK TABLE [table_name] [READ|WRITE];

其中table_name表示資料表名稱,[READ|WRITE]表示可以任選READ(讀鎖)WRITE(寫鎖)中的一種。

當需要解鎖時,只需如下語句:

UNLOCK TABLE;

請書寫 SQL 語句,鎖住imooc_user表,但其他人可讀。

分析:

題幹中指出,他人可讀,因此鎖為讀鎖,通過 LOCK TABLE 鎖住該表即可。

語句:

整理可得語句如下:

LOCK TABLE imooc_user READ;

鎖住後,其他人仍然能夠讀取 imooc_user 表的資料,如下:

# select * from imooc_user;
+----+----------+
| id | username |
+----+----------+
| 1  | peter    |
| 2  | pedro    |
| 3  | jerry    |
| 4  | mike     |
| 5  | tom      |
+----+----------+

測試完畢後,我們一定記得解鎖:

UNLOCK TABLE;

4.2 例2、鎖住 pedro 使用者

對於某一條記錄(某一行),SQL 提交如下方式來加讀鎖:

SELECT * FROM [table_name] WHERE [condition] LOCK IN SHARE MODE;

其中table_name表示資料表名稱,condition表示過濾條件。

如果你要獨佔這一行的資料,可以這樣加上寫鎖:

SELECT * FROM [table_name] WHERE [condition] FOR UPDATE;

注意: 在測試時,你必須在一個事務裡面進行行鎖,否則查詢直接退回,鎖的時間極短。

請書寫 SQL 語句,鎖住 imooc_user 表中使用者pedro,只允許別人讀,不允許別人寫。

分析:

pedro 使用者是表中的一條記錄,因此通過 SELECT … LOCK … 的方式加上行讀鎖,為了方便測試我們以一個事務的方式來操作鎖。

語句:

整理可得語句如下:

BEGIN;
SELECT * FROM imooc_user WHERE id = 1 LOCK IN SHARE MODE;

鎖住該行後,其他使用者可以讀取它卻不能修改它,直到釋放鎖才能修改,如下:

COMMIT;

有時候,我們也需要更加霸道地鎖住 pedro,即不讓人寫,也不讓人讀,這個時候就可以使用寫鎖。

BEGIN;
SELECT * FROM imooc_user WHERE id = 1 FOR UPDATE;

操作完畢後,我們一定記得提交事務以釋放鎖。

COMMIT;

5. 個人經驗

  • 鎖與事務都是面試必備,且二者往往都是彼此關聯。
  • 鎖的內容浩瀚如海,本小節以粒度和管理兩個視角,簡單地介紹了鎖,在實戰部分,我們還會接著討論它。