MySQL之数据库中的行锁与表锁概念

事务并发带来的问题

在并发的情况下,多个事务访问相同记录的情况分为下面三种:

  1. 读-读:多个事务同时读取相同的数据
  2. 写-写:多个事务同时对相同的记录进行写入
  3. 读-写或写-读:部分事务读部分事务写

第一种情况由于并不会对记录产生影响,因此是允许发生的,后两种因为对记录做出修改,会对运行中的其他事务造成影响,因此要采用一些方式避免。

针对写-写的处理

多个事务同时对一条记录做出修改时,会造成脏写的情况,任何一种事务隔离级别都不允许出现这种情况,这种情况采用加锁处理,

多个未提交事务修改同一条记录时,需要让它们排队执行,排队过程通过为该记录加锁实现,锁是一个与记录关联的内存结构,默认一条记录是没有关联的锁结构的,

当一个事务想对记录进行改动时,会先查看该记录是否有关联的锁结构,如果没有则生成一个锁结构与之关联:

锁结构中有两个比较重要的信息:

  1. trx信息:表示锁结构与哪个事务关联
  2. is_waiting:表示事务是否在等待,false代表事务正在运行,true代表在等待

假设事务T1,想对一条记录做出修改,此时发现这条记录没有对应的锁结构,于是创建一个锁结构信息与之关联,is_waiting为false,进一步对记录做出修改,

此时T2也想对该记录做出修改,于是来查看该记录有没有锁结构,发现有的,于是也创建一个锁结构,不过is_waiting为true,随之自己陷入等待:

当T1提交事务后,将自己的锁结构释放掉,并且检查该记录有没有其他的锁结构关联,发现有一个T2,于是将T2的is_waiting设置为false,并将其唤醒,让T2进入执行:

针对写-读或读-写处理

在写读或读写情况下,并发事务会出现脏读、不可重复读、幻读的现象,通过设置相应的隔离级别可以避免这些问题,避免脏读、不可重复读、幻读有如下两种方案:

1. MVCC多版本并发控制

通过MVCC的ReadView,查询语句只能查询到ReadView生成之前已提前事务做出的修改,生成ReadView之后的事务所做的修改提交都是看不到的,

而写操作针对的都是最新的记录版本,因此读历史版本(undo日志)和改动最新记录版本并不会发生冲突。

2. 读/写加锁

不管是读操作还是写操作,都按照上面说的方式加锁进行排队执行,因为都是挨个执行的,上一个事务提交后,这个事务执行,读写肯定都是最新版本,所以不会发生脏读等。

因此,采用MVCC方式,读写操作不会冲突,这种性能是较高的,当时如果加锁的话,就会严重影响性能,一般情况下都会采用MVCC的方式。

何时加锁?

一致性读

通过MVCC进行的读取操作称为一致性读(Consistent Read),或者一致性无锁读(也可称为快照读),所有普通的select语句,在读已提交或可重复读的隔离级别下都是一致性读,例如:

select * from t1;
select * from t1 inner join t2 on t1.id = t2.id
复制代码

一致性读不会对表中的记录进行加锁,其他事务可以自由对记录作出改动。

锁定读

1. 共享锁和独占锁

使用MVCC可以解决事务并发读写的问题,但是有些情况下我们需要使用加锁来做出一些特殊的处理,我们需要让读读之间互不影响,

但是需要写-写、读-写、写-读这几种情况中相互阻塞,针对这些情况分成下面两个锁:

  1. 共享锁(Shared Lock):简称S锁,在事务要读取一条记录时,获取该记录的S锁

  2. 独占锁(Exclusive Lock):简称X锁,也可称为排他锁,在事务要对一条记录改动时,获取该记录的X锁

S锁之间是兼容的,即多个S锁可以一起执行,S锁和X锁是不兼容的,二者必须有一个要进行排队等待。

例如:

  1. T1获取了A记录的S锁
  2. T2想获取A记录的X锁,因为该记录已经有S锁,因此T2陷入等待,等S锁释放才能拿到X锁

上面的情况反过来先X,再S也是一样。

锁定读的写法

在读取记录前为该记录加上S锁或者X锁的方式,被称为锁定读。

S锁的写法

select ... lock in share mode;
复制代码

使用这种语法,会为读取到的记录加上S锁,之后其他事务依然可以获取这些记录的S锁,但是如果有人想获取X锁,就必须等S锁都释放掉。

X锁的写法

select ... for update;
复制代码

使用这种语法,会为读取到的记录加上X锁,之后其他事务不可以获取这些记录的S锁或X锁,需要等待本次事务的X锁释放才能获取到。

写操作对应的锁定读

delete、update、insert三种都是写操作,写操作是必须要获取到X锁之后才可以进行的,下面是三种操作获取锁的过程(可以将获取X锁的过程视为获取X锁的锁定读):

  1. delete:先在B+树中定位到该记录的位置,然后获取该记录的X锁,最后执行delete mark操作,

  2. update:update比较特殊需要分为三种情况

    • 如果修改的列前后大小没有变化,则在B+树中定位到该记录的位置,然后获取记录的X锁,最后在原记录位置进行修改操作

    • 修改的列发生大小变化,则在B+树中定位到该记录的位置,然后获取记录的X锁,将该记录移入垃圾链表,最后插入一条新记录,之后锁结构移到新记录上来

    • 如果修改了主键值,则是将原本的记录删除再insert,加锁操作按照delete和insert来即可

  3. insert:一般情况下,insert操作受到隐式锁保护,不生成锁结构。

多粒度锁

除了给记录加锁,也可以给表加锁,记录锁也被称为行级锁或者行锁,对一个记录加锁只会影响到这条记录,对一个表加锁,被称为表级锁或者表锁,会影响表中所有的记录,前者的粒度比较细,后者的粒度比较粗。

表级S锁

表级S锁与行级类似,只是他的目标是整张表,而不是一些行。

  1. 别的事务可以继续获取该表S锁
  2. 别的事务可以继续获取该表某些记录的S锁
  3. 别的事务不可以继续获取该表X锁
  4. 别的事务不可以继续获取该表某些记录的X锁

表级X锁

表级X锁与行级类似,只是他的目标是整张表,而不是一些行。

  1. 别的事务不可以继续获取该表S锁
  2. 别的事务不可以继续获取该表某些记录的S锁
  3. 别的事务不可以继续获取该表X锁
  4. 别的事务不可以继续获取该表某些记录的X锁

意向锁

表级S锁或X锁存在两个问题,如果获取表级S锁时,表中的某些记录被其他记录获取了X锁怎么办,如果获取表级X锁时,表中的某些记录被其他记录获取了S锁怎么办,

因为S和X是互斥的,虽然一个是表一个是行,但也不许有这种情况发生,但是如何知道获取表级锁时,表中的记录有没有被别事务正在占用的锁呢?不可能遍历表中的所有数据,那样太慢了,因此产生了意向锁的概念。

意向共享锁(IS锁)

Intention Shared Lock,当事务在某条记录上添加S锁时,需要先在表上添加IS锁。

意向独占锁(IX锁)

Intention Exclusive Lock,当事务在某条记录上添加X锁时,需要先在表上添加IX锁。

有了意向锁后,每次获取相应的表级锁时,仅需判断表上面有没有冲突的意向锁即可,例如加表级X锁时,看看表上有没有IS锁和IX锁,加表级S锁时,看看表上有没有IX锁。

注意:锁记录在添加IS锁时不关心表上有没有IX锁,添加IX锁时也并不关心表上有没有IS锁,因为他们仅仅是对表标记这个表中的记录正在被上锁,IS、IX锁仅对表级加锁有用,对行级没用,行级最终判断自己要去获取的记录有没有被其他事务占用即可。

表级别锁的兼容性:

兼容性XIXSIS
X不兼容不兼容不兼容不兼容
IX不兼容兼容不兼容兼容
S不兼容不兼容兼容兼容
IS不兼容兼容兼容兼容

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL行锁表锁是用于控制并发访问的锁机制。它们分别用于锁定数据库的行和表,以确保在并发环境下的数据一致性。 1. 行锁(Row Lock):行锁是在事务级别下对数据库的行进行加锁。当一个事务对某一行进行修改时,会获取该行的行锁,并阻塞其他事务对该行的修改操作。行锁可以防止多个事务同时修改同一行数据,确保数据的一致性。MySQL行锁是在存储引擎层实现的,不同存储引擎对行锁的支持程度可能不同。 2. 表锁(Table Lock):表锁是在事务级别下对整个表进行加锁。当一个事务对某一表进行修改时,会获取该表的表锁,并阻塞其他事务对该表的修改操作。表锁可以防止多个事务同时修改整个表,确保数据的一致性。表级锁是MySQL最基本的锁机制,适用于低并发场景或者对表进行全表扫描等操作。 需要注意的是,行锁表锁是互斥的,同一时间只能有一个事务持有某一行或表的锁。行锁粒度更细,可以减少锁冲突,提高并发性能,但也会带来更多的开销。而表锁粒度更大,锁的冲突概率较高,对并发性能影响较大。 在实际应用,根据并发访问的特点和需求,需要合理选择行锁表锁的使用方式。可以根据具体场景使用不同的锁机制,或者通过调整事务隔离级别、优化查询语句等手段来提高并发性能。同时,还可以通过索引优化、拆分大表等方式来减少锁冲突,提高数据库的并发处理能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值