文章目录
- 特点
- 适用场景
- 不足
- 锁机制
- 表级锁的类型
- 锁的获取和释放
- 锁的等待队列
- 示例
- 共享锁
- 排他锁
- READ LOCAL
MyISAM是MySQL的一种存储引擎,它以其简单性和高速度而著称。在早期的MySQL版本中,MyISAM广泛使用,尤其是在那些以读操作为主的应用场景中。然而,随着InnoDB存储引擎的成熟和普及,MyISAM的使用逐渐减少。
特点
- 简单性
- 实现简单:MyISAM的实现相对简单,没有复杂的事务管理和外键约束,因此在某些场景下更容易维护和管理。
- 轻量级:MyISAM占用的系统资源较少,适合资源受限的环境。
- 高性能
- 读操作优化:MyISAM特别适合以读操作为主的场景,因为它在读取数据时性能非常高。
- 索引优化:MyISAM使用B+树索引,支持全文索引,能够高效处理大规模数据集。
- 表级锁
- 表级锁:MyISAM使用表级锁(Table-Level Locking),这意味着写操作时会锁定整个表,而不是表中的某一行或某几行。这在高并发写操作的场景下可能会导致性能瓶颈。
- 并发性:虽然读操作可以并发进行,但写操作会阻塞所有其他读写操作。
- 全文索引
- 全文索引:MyISAM支持全文索引(Full-Text Index)这使得它在搜索引擎和内容管理系统中非常有用。
- 搜索效率:全文索引可以显著提高文本搜索的效率。
- 压缩表
- 压缩表:MyISAM支持创建压缩表,这可以节省磁盘空间,但压缩表只支持读操作,不支持写操作。
- 空间效率:压缩表在存储大量历史数据时非常有用。
- 修复和恢复
- 修复工具:MyISAM提供了一些工具(如REPAIR TABLE)来修复损坏的表
- 恢复机制:虽然MyISAM没有事务日志,但它可以通过备份和恢复机制来恢复数据。
适用场景
- 读密集型应用:MyISAM特别适合以读操作为主的场景,如网站的静态内容、日志分析等。
- 全文搜索:MyISAM的全文索引功能使其在搜索引擎和内容管理系统中非常有用。
- 资源受限环境:在资源受限的环境中,MyISAM的轻量级特性使其成为一个不错的选择。
- 历史数据存储:MyISAM的压缩表功能使其适合存储大量历史数据。
不足
- 不支持事务:这意味着在需要事务一致性的场景下,它不是一个合适的选择。
- 不支持外键:这在需要数据完整性的场景下是一个明显的不足。
- 高并发写操作:由于MyISAM使用表级锁,高并发写操作会导致性能瓶颈,不适合写密集型应用。
- 数据恢复:MyISAM没有事务日志,数据恢复依赖于备份和修复工具,恢复过程可能比较复杂。
锁机制
MyISAM存储引擎主要使用表级锁(Table-Level Locking)。表级锁是一种粗粒度的锁机制,它在执行某些操作时会锁定整个表,而不是表中的某一行或某几行。
表级锁的类型
MyISAM支持两种类型的表级锁:
- 共享锁(Shared Locks, S Locks):
- 共享锁允许多个事务同时读取同一个表,但不允许任何事务修改表中的数据。
- 共享锁是读操作的默认锁类型
- 排他锁(Exclusive Locks, X Locks):
- 排他锁不允许任何其他事务读取或修改表中的数据
- 排他锁是写操作的默认锁类型
锁的获取和释放
- 读操作:当一个事务读取表中的数据时,它会请求一个共享锁。如果表上没有排他锁,共享锁会被立即授予。
- 写操作:当一个事务写入表中的数据时,它会请求一个排他锁。如果表上没有其他锁(无论是共享锁还是排他锁),排他锁会被立即授予。
语法:
LOCK TABLES table_name lock_type [, table_name lock_type ...];
-
table_name 是要锁定的表的名称。
-
lock_type 指定锁定的类型,主要有两种:READ 和 WRITE。
- READ 锁(共享锁)
允许多个事务同时读取表中的数据。
阻止任何事务对表进行写操作(如插入、更新、删除)。 - WRITE 锁(排他锁)
禁止其他事务对表进行任何读写操作。
通常用于写操作,确保数据的一致性和完整性。
- READ 锁(共享锁)
# 锁定单个表
LOCK TABLES users WRITE;
# 锁定多个表
LOCK TABLES users WRITE, orders READ;
# 解锁表
UNLOCK TABLES;
锁的等待队列
当一个事务请求的锁无法立即获得时,它会被放入一个等待队列中。MySQL会按照请求的顺序依次处理这些等待请求。如果一个事务请求了一个排他锁,而表上已经有共享锁存在,那么这个事务必须等待所有共享锁释放后才能获得排他锁。
示例
首先,开启两个终端窗口,分别称为窗口A和窗口B。两个窗口都登录到MySQL数据库并切换到test库。
准备工作:
create table isam1 (id int(11), name varchar(10)) engine=MyISAM;
create table isam2 (id int(11), name varchar(10)) engine=MyISAM;
insert into isam1 value(1, 'a1');
insert into isam2 value(1, 'a2');
共享锁
时间 | 窗口A | 窗口B |
---|---|---|
t1 | lock tables isam1 read; select * from isam1; | |
t2 | select * from isam1;//立即查到结果 | |
t3 | unlock tables; |
时间 | 窗口A |
---|---|
t1 | lock tables isam1 read; select * from isam1; |
t2 | select * from isam2; //ERROR |
t3 | update isam1 set name = ‘a11’ where id=1; //ERROR |
t4 | unlock tables; |
> select * from isam2;
ERROR 1100 (HY000): Table 'isam2' was not locked with LOCK TABLES
> update isam1 set name = 'a11' where id=1;
ERROR 1099 (HY000): Table 'isam1' was locked with a READ lock and can't be updated
排他锁
时间 | 窗口A | 窗口B |
---|---|---|
t1 | lock tables isam1 write; select * from isam1; | |
t2 | select * from isam1;//阻塞 或 update isam1 set name = ‘a11’ where id=1; //阻塞 | |
t3 | unlock tables; |
窗口A获取表isam1的排他锁,窗口B将无法查询或修改表中数据。
READ LOCAL
READ LOCAL锁定模式是LOCK TABLES语句的一个选项,它允许读取锁定表中的数据,但与其他事务的交互有所不同。
- 读取本地缓冲区:当使用READ LOCAL锁定时,MySQL会将锁定表的数据缓存到本地内存中。这意味着读取操作会从这个本地缓存中读取数据,而不是直接从磁盘读取。
- 允许并发读取:即使在锁定状态下,其他事务仍然可以读取该表的数据。这与普通的READ锁定不同,后者完全禁止其他事务读取锁定的表。
- 防止其他事务修改:与READ锁定类似,READ LOCAL锁定同样阻止其他事务对表进行写操作(如插入、更新、删除)。
时间 | 窗口A | 窗口B |
---|---|---|
t1 | lock tables isam1 read local; select * from isam1; | |
t2 | insert into isam1 value(2, ‘a2’); //ERROR | |
t3 | select * from isam1;//立即查到结果 insert into isam1 value(3, ‘a3’); //插入成功 select * from isam1;//立即查到结果且返回新插入的数据 | |
t4 | select * from isam1; //查询成功,但不显示窗口B刚插入的数据 | |
t3 | unlock tables; |
窗口A:
窗口B: