MySQL的锁机制

    xiaoxiao2025-04-23  15

    前言

    并发是Java开发一个重要的点,而数据库的并发也显得非常重要,而并发中,锁是一个非常重要的知识点。在MySQL数据库中,锁分为行锁,页锁,表锁,写锁,读锁。下面简单看看行锁,页锁,表锁的差别和特性。 表锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 页锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般 。 行锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 每个级别的锁都有各自的优缺点,所以具体用什么锁还是得看具体情况。 而在MySQL数据库中,常常被提及也被用的最多的是MyISAM表锁和InnoDB行锁。

    MyISAM表锁

    对于MyISAM锁,有读锁和写锁之分。当一个session获得了读锁,那么会有以下性质: 1.该session无法对该表进行写操作; 2.该session可以对表进行读操作; 3.该session无法对没有锁定的表进行读,写操作; 4.其他session可以对该表进行读操作; 5.其他session对该表的写操作会出现阻塞,需要等待。 当一个session获得了写锁,那么会有以下性质: 1.该session可以对表进行查询,可以进行增删改查; 2.其他session对该表的查询会出现阻塞,需要等待。

    并发插入

    当一个session获得一个读锁时,其实是可以实现读和插入的并发的,就是其他session可以在表末尾插入字段,这时候需要通过Concurrent Inserts系统变量来设置。 当concurrent_insert设置为0时,不允许并发插入。 当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。 当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。 当一个session获得一个表的读锁时,加上local,就表明其他session可以同时进行插入并发,加入local的读锁具有以下性质: 1.当前session无法对该表进行增删改操作,插入也不行; 2.当前session无法查询未锁定的表; 3.当前session可以对该表进行读操作 4.其他session可以在该表的末尾添加记录; 5.当前session无法查询到其他session对该表的并发插入结果; 6.其他session可以查询该表; 7.其他session对该表的更新会出现阻塞,需要等待。

    MyISAM的其他特性

    MyISAM对于读锁和写锁,写锁的优先级都是高于读锁,当同时进行写锁和读锁的需求时,会先处理写锁,所以当系统需要大量更新和读操作的时候,就不太适合使用MyISAM锁。

    InnoDB锁

    InnoDB与MyISAM最大的区别有以下两个: 1.MyISAM不支持事务,而InnoDB支持事务; 2.MyISAM使用的是表锁,而InnoDB使用的是行锁。 首先,对于InnoDB支持事务处理这一点有以下性质: 1.原子性:就是操作要么全部执行,要么不执行。例如,如果创建一个customer表和一个Oder表分别表示顾客信息和相应订单信息,那么假如现在有一个新顾客下了一个新订单,现在分别需要在两个表里面插入两个记录,若customer表插入失败,那么order表也不需要插入了,因为顾客都不存在,订单更加不存在。所以这个时候如果将两个插入语句放在一个事物里面,那么如果customer表插入失败,那么order表也不会存在相应数据,这就保证了表的原子性。 2.一致性:在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以操持完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。 3.隔离性:所有的事务之间是互不干扰的,事务也不受外界干扰。 4.持久性:事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

    InnoDB的行锁模式

    InnoDB有以下两种形式的行锁: 共享锁(S):也就是读锁,当一个事务获得一个记录的共享锁的时候,有以下性质: 1.该事务可以对该纪录进行读操作,但是不能进行更新操作; 2.其他事务无法对该记录加排他锁,但是可以加共享锁,即其他session可以对该纪录进行读操作,但是不可以进行更新操作。 排它锁(X):也就是写锁,当一个事务获得一个一个排他锁后会有以下性质: 1.该事物可以对该行进行查询和更新操作; 2.其他事务无法对该行加共享锁或者排它锁,也就是其他事务无法对该行进行写操; 3.其他事务在不添加锁的情况下是可以进行查询操作的。因为在MySQL中,当执行delete,update,insert的时候是会自动加排他锁的,而select默认操作的命令时,就不会加排他锁,也不会加共享锁,所以其他事务是可以对加锁行进行查询操作的。

    InnoDB行锁形式和特性

    这里要强调的一点是,InnoDB是通过在索引上的索引项添加锁的形式添加行锁的,对于不同情况的表,InnoDB的锁也有所不同,具体为: 1.如果表里面没有添加索引,那么InnoDB使用的是表索引,而不是行索引; 2.由于MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。例如:在customer表中,id字段存在索引,name字段不存在索引,事务一执行

    select * from customer where id=1 and name='张三' for update;

    而事务2执行:

    select * from customer where id=1 and name='李四' for update;

    那么,事务2的执行也会出现阻塞,需要等待事务1释放锁后才能执行,即使他们查询的不是同一条记录,但是他们使用的是相同的索引。(由于select语句默认是没有添加锁的,所以这里的for update是显示地对行添加排它锁)。 3.当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,另外,不论是使用主键索引、唯一索引或普通索引,InnoDB都会使用行锁来对数据加锁。 当表里面存在不同的索引的时候,如果根据不同索引搜索出来的是相同的行,那么也会出现阻塞,需要等待。 4.如果执行查询的时候,MySQL判断不使用索引的时候查询结果会更快,那么就不会通过索引查询。

    最新回复(0)