紙上得來終覺淺,絕知此事要躬行。mysql
從對數據操做的粒度分 :sql
從對數據操做的類型分:數據庫
MySQL的鎖機制比較簡單,其最顯著的特色是不一樣的存儲引擎支持不一樣的鎖機制。下表中羅列出了各存儲引擎對鎖的支持狀況:併發
存儲引擎 | 表級鎖 | 行級鎖 | 頁面鎖 |
---|---|---|---|
MyISAM | 支持 | 不支持 | 不支持 |
InnoDB | 支持 | 支持 | 不支持 |
MEMORY | 支持 | 不支持 | 不支持 |
BDB | 支持 | 不支持 | 支持 |
特性:性能
鎖類型 | 特色 |
---|---|
表級鎖 | 偏向MyISAM 存儲引擎,開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。 |
行級鎖 | 偏向InnoDB 存儲引擎,開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的機率最低,併發度也最高。 |
頁面鎖 | 開銷和加鎖時間界於表鎖和行鎖之間;會出現死鎖;鎖定粒度界於表鎖和行鎖之間,併發度通常。 |
MyISAM
表鎖MyISAM
在執行查詢語句SELECT
前,會自動給涉及的全部表加讀鎖,在執行更新操做UPDATE、DELETE、INSERT
前,會自動給涉及的表加寫鎖,這個過程並不須要用戶干預,所以,用戶通常不須要直接用 LOCK TABLE
命令給 MyISAM 表顯式加鎖。測試
顯示加表鎖語法:線程
加讀鎖 : lock table table_name read; 加寫鎖 : lock table table_name write;
雖然MyIASM
默認加了表鎖,可是咱們仍然能夠手動加鎖,具體經過案例來了解一下加鎖以後,咱們操做數據庫會有什麼影響。code
在進行測試以前咱們須要準備測試環境和相關數據庫以及表,而且把MySQL
的存儲引擎指定爲MyISAM
,以下先建立一個數據庫並切換到數據庫:blog
create database demo2 default charset=utf8;
接着建立表,本次咱們測試的是MyISAM
存儲引擎,因此要建立表時要指定存儲引擎(說明存儲引擎是做用於表,而不是做用於數據庫,也就是說一個數據庫有多個表,而多個表可使用不一樣的存儲引擎)rem
CREATE TABLE `tb_book` ( `id` INT(11) auto_increment, `name` VARCHAR(50) DEFAULT NULL, `publish_time` DATE DEFAULT NULL, `status` CHAR(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=myisam DEFAULT CHARSET=utf8 ; # 插入數據 INSERT INTO tb_book (id, name, publish_time, status) VALUES(NULL,'高性能MySQL','2088-08-01','1'); INSERT INTO tb_book (id, name, publish_time, status) VALUES(NULL,'MySQL技術內幕','2088-08-08','0'); CREATE TABLE `tb_user` ( `id` INT(11) auto_increment, `name` VARCHAR(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=myisam DEFAULT CHARSET=utf8 ; # 插入數據 INSERT INTO tb_user (id, name) VALUES(NULL,'張三'); INSERT INTO tb_user (id, name) VALUES(NULL,'李四');
讀鎖
數據準備完成接下來咱們進行測試,使用兩個客戶端鏈接數據庫。
客戶端一:
tb_book
表的讀鎖lock table tb_book read;
select * from tb_book; mysql> select * from tb_book; +----+-------------------+--------------+--------+ | id | name | publish_time | status | +----+-------------------+--------------+--------+ | 1 | 高性能MySQL | 2088-08-01 | 1 | | 2 | MySQL技術內幕 | 2088-08-08 | 0 | +----+-------------------+--------------+--------+ 2 rows in set (0.00 sec)
能夠正常執行,查詢出數據。
客戶端二:
select * from tb_book; mysql> select * from tb_book; +----+-------------------+--------------+--------+ | id | name | publish_time | status | +----+-------------------+--------------+--------+ | 1 | 高性能MySQL | 2088-08-01 | 1 | | 2 | MySQL技術內幕 | 2088-08-08 | 0 | +----+-------------------+--------------+--------+ 2 rows in set (0.00 sec)
也能夠正常查詢數據
客戶端一:
select * from tb_user; mysql> select * from tb_user; ERROR 1100 (HY000): Table 'tb_user' was not locked with LOCK TABLES
提示tb_user
沒有加鎖,沒法獲取數據
客戶端二:
select * from tb_user; mysql> select * from tb_user; +----+--------+ | id | name | +----+--------+ | 1 | 張三 | | 2 | 李四 | +----+--------+ 2 rows in set (0.00 sec)
能夠正常查詢出未鎖定的表
客戶端一:
insert into tb_book values(null,'Mysql高級','2088-01-01','1'); mysql> insert into tb_book values(null,'Mysql高級','2088-01-01','1'); ERROR 1099 (HY000): Table 'tb_book' was locked with a READ lock and can't be updated
執行插入, 直接報錯,因爲當前tb_book 得到的是讀鎖,不能執行更新操做。
客戶端二:
insert into tb_book values(null,'Mysql高級','2088-01-01','1');
執行語句阻塞,等待中。
當在客戶端一中釋放鎖指令unlock tables
後 , 客戶端二中的 inesrt
語句當即執行。
寫鎖
客戶端一:
lock table tb_book write;
select * from tb_book; mysql> select * from tb_book; +----+-------------------+--------------+--------+ | id | name | publish_time | status | +----+-------------------+--------------+--------+ | 1 | 高性能MySQL | 2088-08-01 | 1 | | 2 | MySQL技術內幕 | 2088-08-08 | 0 | | 3 | Mysql高級 | 2088-01-01 | 1 | +----+-------------------+--------------+--------+ 3 rows in set (0.00 sec)
update
操做mysql> update tb_book set name = 'MySQL' where id = 3; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0
insert
操做mysql> insert into tb_book values(null,'Python','2088-01-01','1'); Query OK, 1 row affected (0.00 sec)
delete
操做mysql> delete from tb_book where id = 4; Query OK, 1 row affected (0.00 sec)
當前客戶端處於write lock
,其增刪改查都正常執行
客戶端二:
select * from tb_book;
此時查詢操做處於阻塞狀態。
客戶端三:
update tb_book set name = 'Java' where id = 3;
也處於阻塞狀態。
當咱們把客戶端一的表解鎖,則客戶端二的查詢操做和客戶端三的更新操做馬上執行。
客戶端一:
tb_book
表的讀鎖lock table tb_book read;
客戶端二:
tb_book
表的讀鎖lock table tb_book read;
此時客戶端一,只能讀取加鎖的表,客戶端二一樣只能讀取加鎖的表,都沒法更新表。
tb_book
表的寫鎖lock table tb_book wtite;
因爲客戶端一已經上了讀鎖,此時客戶端二上寫鎖會阻塞。
客戶端一:
tb_book
表的讀鎖,而後繼續執行寫鎖lock table tb_book read; lock table tb_book write;
此時客戶端一能夠對加鎖的表執行增刪改查,客戶端二對加鎖的表增刪改查阻塞。
MyISAM
表的讀操做,不會阻塞其餘用戶對同一表的讀請求,但會阻塞對同一表的寫請求MyISAM
表的寫操做,則會阻塞其餘用戶對同一表的讀和寫操做簡而言之,就是讀鎖會阻塞寫,可是不會阻塞讀。而寫鎖,則既會阻塞讀,又會阻塞寫。
此外,MyISAM 的讀寫鎖調度是寫優先,這也是MyISAM不適合作寫爲主的表的存儲引擎的緣由。由於寫鎖後,其餘線程不能作任何操做,大量的更新會使查詢很可貴到鎖,從而形成永遠阻塞。
show open tables;
In_user
:表當前被查詢使用的次數。若是該數爲零,則表是打開的,可是當前沒有被使用。
Name_locked
:表名稱是否被鎖定。名稱鎖定用於取消表或對錶進行重命名等操做。
show status like 'Table_locks%'; mysql> show status like 'Table_locks%'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | Table_locks_immediate | 139 | | Table_locks_waited | 0 | +-----------------------+-------+ 2 rows in set (0.00 sec)
Table_locks_immediate
:指的是可以當即得到表級鎖的次數,每當即獲取鎖,值加1。
Table_locks_waited
:指的是不能當即獲取表級鎖而須要等待的次數,每等待一次,該值加1,此值高說明存在着較爲嚴重的表級鎖爭用狀況。