网站首页 > 文章中心 > 其它

mysql怎么使用行锁

作者:小编 更新时间:2023-09-05 10:23:47 浏览量:10人看过

如何基于MySQL的行锁来实现悲观锁?

首先仅仅加上selelct for update是不足够的,还必须利用事务保证操作的原子性.

保证不会出现多线程并发问题:

仅仅使用事务保证原子性:

其他线程还是可以获取记录进行覆盖.

仅仅使用了行锁:

MySQL的每一个操作都是开启事务的,并且会自动提交,仅仅加入行锁,第一步操作后就事务提交释放,依旧会被覆盖记录.

mysql怎么使用行锁-图1

MySQL中innodb的行锁算法

众所周知,innodb是默认行锁,当然也支持表锁.如下是对于行锁的算法进行的一些实验.

锁的算法为:我知道是行锁,但是是如何锁的,锁多少数据

Innodb锁算法规则如下:

在可重复读隔离级别下,innodb默认使用的是next-key lock算法,当查询的索引是主键或者唯一索引的情况下,才会退化为record lock,在使用next-key lock算法时,不仅仅会锁住范围,还会给范围最后的一个键值加一个gap lock.

其中lockmode中的X锁为左边会话中的锁,因为需要显式的commit之后才会释放锁,第二个S锁,为右边的共享锁,因为主键ID为1的已经被锁住了,所以处于锁等待状态,锁的类型为record lock

所以目前被锁住的记录为:

当使用范围条件进行更新时,此时肯定是需要加X锁的,我是用的也是主键,所以按照理论应该是加的record lock ,但是却加了gap lock,因为插入值为10的阻塞了,查看information 也提示X.GAP

这个有点晕为啥主键变成了next-key lock ,不应该是record lock么?

在知乎看到的一个解释:

即,在无论使用主键索引还是非主键索引的时候,请求共享锁或者排他锁,innodb会给范围内的记录加锁,而范围内的间隙也会被加锁,

假如执行如下:

那么这个时候执行

执行

幻读是同一事务下,连续执行两次同样的sql可能导致不同的结果,第二次返回的数据可能导致以前不存在的行.

同时一般会问它和脏读的区别,脏读为读取到其他事务未提交的数据,但是幻读是读取的其他事务已经提交的数据.

reference:

mysql 的锁以及间隙锁

mysql 为并发事务同时对一条记录进行读写时,提出了两种解决方案:

①.)使用 mvcc 的方法,实现多事务的并发读写,但是这种读只是"快照读",一般读的是历史版本数据,还有一种是"当前读",一般加锁实现"当前读",或者 insert、update、delete 也是当前读.

快照读:就是select

当前读:特殊的读操作,插入/更新/删除操作,属于当前读,处理的都是当前的数据,需要加锁.

mysql 在 RR 级别怎么处理幻读的呢?一般来说,RR 级别通过 mvcc 机制,保证读到低于后面事务的数据.但是 select for update 不会触发 mvcc,它是当前读.如果后面事务插入数据并提交,那么在 RR 级别就会读到插入的数据.所以,mysql 使用 行锁 + gap 锁(简称 next-key 锁)来防止当前读的时候插入.

Gap Lock在InnoDB的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生.

Innodb自动使用间隙锁的条件:

MySQL从入门到精通(九) MySQL锁,各种锁

全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将阻塞.其典型的使用场景就是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性.但是对数据库加全局锁是有弊端的,如在主库上备份,那么在备份期间都不能执行更新,业务会受影响,第二如果是在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志,会导致主从延迟.

解决办法是在innodb引擎中,备份时加上--single-transaction参数来完成不加锁的一致性数据备份.

添加全局锁: flush tables with read lock; 解锁 unlock tables.

表级锁,每次操作会锁住整张表.锁定粒度大,发送锁冲突的概率最高,并发读最低,应用在myisam、innodb、BOB等存储引擎中.表级锁分为: 表锁、元数据锁(meta data lock, MDL)和意向锁.

表锁又分为: 表共享读锁 read lock、表独占写锁write lock

语法: 1、加锁 lock tables 表名 ... read/write

元数据锁,在加锁过程中是系统自动控制的,无需显示使用,在访问一张表的时候会自动加上,MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作.为了避免DML和DDL冲突,保证读写的正确性.

查看元数据锁:

select object_type,object_schema,object_name,lock_type,lock_duration from performance_schema_metadata_locks;

意向锁,为了避免DML在执行时,加的行锁与表锁的冲突,在innodb中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查.意向锁分为,意向共享锁is由语句select ... lock in share mode添加.意向排他锁ix,由insert,update,delete,select...for update 添加.

select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from performance_schema.data_lock;

行级锁,每次操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最高,并发读最高,应用在innodb存储引擎中.

innodb的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁,对于行级锁,主要分为以下三类:

①.、行锁或者叫record lock记录锁,锁定单个行记录的锁,防止其他事物对次行进行update和delete操作,在RC,RR隔离级别下都支持.

innodb实现了以下两种类型的行锁

①.、共享锁 S: 允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁.

insert 语句 排他锁 自动添加的

update语句 排他锁 自动添加

delete 语句 排他锁 自动添加

select 正常查询语句 不加锁 ...

select ...lock in share mode 共享锁 需要手动在select 之后加lock in share mode

select ...for update 排他锁 需要手动在select之后添加for update

默认情况下,innodb在repeatable read事务隔离级别运行,innodb使用next-key锁进行搜索和索引扫描,以防止幻读.

间隙锁唯一目的是防止其它事务插入间隙,间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用的间隙锁.

MySQL - for update 行锁 表锁

for update 的作用是在查询的时候为行加上排它锁,当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新.

它的典型使用场景是 高并发并且对于数据的准确性有很高要求 ,比如金钱、库存等,一般这种操作都是很长一串并且开启事务的,假如现在要对库存进行操作,在刚开始读的时候是1,然后马上另外一个进程将库存更新为0了,但事务还没结束,会一直用1进行后续的逻辑,就会有问题,所以需要用for upate 加锁防止出错.

行锁的具体实现算法有三种:record lock、gap lock以及next-key lock.

只在可重复读或以上隔离级别下的特定操作才会取得 gap lock 或 next-key lock,在 Select、Update 和 Delete 时,除了基于唯一索引的查询之外,其它索引查询时都会获取 gap lock 或 next-key lock,即锁住其扫描的范围.主键索引也属于唯一索引,所以主键索引是不会使用 gap lock 或 next-key lock

for update 仅适用于InnoDB,并且必须开启事务,在begin与commit之间才生效.

select 语句默认不获取任何锁,所以是可以读被其它事务持有排它锁的数据的!

InnoDB 既实现了行锁,也实现了表锁.

当有明确指定的主键/索引时候,是行级锁,否则是表级锁

明确指定主键,并且有此记录,行级锁

无主键/索引,表级锁

主键/索引不明确,表级锁

明确指定主键/索引,若查无此记录,无锁

参考博文:

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章