MYSQL锁按照锁的粒度分,分为以下三类:
-
全局锁:锁定数据库中的所有表。
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态
-
表级锁:每次操作锁住整张表。
表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低 , 对于表级锁,主要分为以下三类:
-
表锁 :
-
表共享读锁 lock tables 表名 read/write
-
表排他写锁 lock tables 表名 write
-
-
元数据锁 :(单纯的概念,无需多管)
-
元数据锁加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上 , 主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作
-
-
意向锁 : 为一条数据加行锁的情况下, 同时获取表的意向锁 , 其他事物再来获取表锁 , 可以方便的判断是否可以获取锁 , 使用意向锁来减少表锁的检查。意向锁的存在是为了协调行锁和表锁的关系,用于优化InnoDB加锁的策略。意向锁的主要功能就是:避免为了判断表是否存在行锁而去全表扫描。(也是系统来操作的,无需多管)
意向锁是由InnoDB在操作数据之前自动加的,不需要用户干预;-
意向共享锁(IS): 由语句 select ... lock in share mode添加 。 与 表锁共享锁(read)兼容,与表锁排他锁(write)互斥。
-
意向排他锁(IX): 由insert、update、delete、select...for update添加 。与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。
-
-
-
行级锁:每次操作锁住对应的行数据。
行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高 , 行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。
-
行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持。
-
间隙锁(Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持
-
临键锁(Next-Key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。
死锁:
-
产生的原因:事物A占用着a锁(锁定某一数据)请求b锁的资源,此时事物B占用着b锁请求a锁的资源。此时两个事物都没办法请求到资源就会出现死锁的情况。
系统中往往与数据库的交互杂乱无章,在报这种错误时也不会具体指出那一次事物占用了另外一个事物。这时候就可以去使用SHOW ENGINE INNODB STATUS命令:该命令会返回一个包含详细信息的InnoDB状态报告,其中包含了当前的死锁信息。也可以去使用工具pt-deadlock-logger,这个工具我没具体使用过。
解决方案:目前我个人的两种解决方案
1、开启死锁检测(默认开启的,你可以查看是否开启,命令show variables;查看innodb_deadlock_detect),然后对报错后做补偿机制。
2、事物开始时直接对需要使用资源一次直接锁定,例如上面例子中的事物A开始就直接锁定a和b,事物B开始就直接锁定a和b。