共享锁、排他锁、乐观锁、悲观锁,行级锁以及表级锁 笔记

🔒SQL:共享锁、排他锁、乐观锁、悲观锁,行级锁以及表级锁

🔒锁的产生

基础常识

首先,你需要对于数据库系统原理有一定的认识,你需要了解事务的概念,什么是事务?

⚙️事务 : 指的是满足 ACID 特性的一系列操作。在数据库中,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。

事务的ACID 特性:原子性(Atomicity)、一致性(Consistency)、一致性(Consistency)、持久性(Durability)

  • 🚩原子性:

    ​ 事务被视为不可分割的最小单元,要么全部提交成功,要么全部失败回滚

  • 🚩一致性:

​ 事务执行前后都保持一致性状态。在一致性状态下,所有事务对一个数据的读取结果都是相同的

  • 🚩隔离性:

​ 一个事务所做的修改在最终提交以前,对其它事务是不可见的

  • 🚩持久性:

​ 一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。可以通过数据库备份和恢复来保证 持久性

📉出现问题

​ 在并发环境下,一个事务如果受到另一个事务的影响,那么事务操作就无法满足一致性条件。就可能出现如下的情况

1.丢失修改

T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。

2. 读脏数据

T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。

3. 不可重复读

T1 读取一个数据,T2 对该数据做了修改。如果 T1 再次读取这个数据,此时读取的结果和和第一次读取的结果不同。

4. 幻影读

T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。

📈解决办法

产生并发不一致性问题主要原因是破坏了事务的隔离性,解决方法是通过并发控制来保证隔离性。

可串行化调度

在没有并发的情况下,事务以串行的方式执行,互不干扰,因此可以保证隔离性。在并发的情况下,如果能通过并发控制,让事务的执行结果和某一个串行执行的结果相同,就认为事务的执行结果满足隔离性要求,也就是说是正确的。把这种事务执行方式称为 可串行化调度

封锁

并发控制可以通过封锁来实现,但是封锁操作都要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题。


🔒锁的类型

🥇排它锁(X锁)与共享锁(S锁)

🔓共享锁(S锁)

共享锁(Shared),简写为 S 锁,又称读锁

一个事务对数据对象 A 加了 S 锁,可以对 A 进行读取操作,但是不能进行更新操作。加锁期间其它事务能对 A 加 S 锁,但是不能加 X 锁。

🔐排它锁(X锁)

排他锁(X锁)又称写锁。:排它锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。

一个事务对数据对象 A 加了 X 锁,就可以对 A 进行读取和更新。加锁期间其它事务不能对 A 加任何锁。

🥈乐观锁 与 悲观锁

😀乐观锁

乐观锁不是数据库自带的,需要我们自己去实现,是一种思想。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新时,去对比版本(version)字段是否相等,去判断是否有冲突了。

通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。也就是先查询出那条记录,获取出version字段,如果要对那条记录进行操作(更新),则先判断此刻version的值是否与刚刚查询出来时的version的值相等,如果相等,则说明这段期间,没有其他程序对其进行操作,则可以执行更新,将version字段的值加1;如果更新时发现此刻的version值与刚刚获取出来的version的值不相等,则说明这段期间已经有其他程序对其进行操作了,则不进行更新操作。

举例:

下单操作包括3步骤:

1.查询出商品信息

select (status,status,version) 
from t_goods 
where id=#{id}

2.根据商品信息生成订单

3.修改商品status为2

update t_goods
set status=2,version=version+1
where id=#{id} 
and version=#{version};

除了自己手动实现乐观锁之外,现在网上许多框架已经封装好了乐观锁的实现,如hibernate,需要时,可能自行搜索"hiberate 乐观锁"试试看。

😞悲观锁

与乐观锁相对应的就是悲观锁了。悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,所以悲观锁需要耗费较多的时间。悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。

刚刚说了,对于悲观锁,一般数据库已经实现了,共享锁和排它锁也属于悲观锁,那么共享锁在mysql中是通过什么命令来调用呢。通过在执行语句后面加上lock in share mode就代表对某些资源加上共享锁了。比如,我这里通过mysql打开两个查询编辑器,在其中开启一个事务,并不执行commit语句city表DDL如下:

 ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8
begin
SELECT * from city where id = "1" lock in share mode

#然后在另一个查询窗口中,对id为1的数据进行更新
update city set name="北京" where id ="1"
#此时,操作界面进入了卡顿状态,过几秒后,也提示错误信息
[SQL]update city set name="上海" where id ="1"
[Err] 1205 - Lock wait timeout exceeded; try restarting transaction

那么证明,对于id=1的记录加锁成功了,在上一条记录还没有commit之前,这条id=1的记录被锁住了,只有在上一个事务释放掉锁后才能进行操作,或用共享锁才能对此数据进行操作。

🥉行级锁 与 表级锁

📑行级锁

行锁,由字面意思理解,就是给某一行加上锁,也就是一条记录加上锁。

比如之前演示的共享锁语句

SELECT * from city where id = "1" lock in share mode

由于对于city表中,id字段为主键,就也相当于索引。执行加锁时,会将id这个索引为1的记录加上锁,那么这个锁就是行锁。

📙表级锁

表锁,和行锁相对应,给这个表加上锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值