Mysql的事务与锁机制简介

1、事务

1.1、什么是事务?

事务是由一组SQL语句组成的逻辑处理单元,通常包含多个操作。

1.2、事务的ACID属性

原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行(这个是针对于操作的)。
一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规 则都必须应用于事务的修改,以保持数据的完整性(这个是针对于数据的)。
隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独 立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

1.3、并发事务会带来的问题

并发会带来类似于下面四个问题,如下详述:
更新丢失(Lost Update)或脏写:
就比如说事务A先update了K行,但是他还未提交,这时候事务B又更新了K行,然后先于事务A提交了,这就会丢失事务B所提交的结果。如下图所示:

在这里插入图片描述


脏读(Dirty Reads):
事务A读取到了事务B已经修改但尚未提交的数据。如果此时事务B回滚,那么这条数据就应该不存在,不符合事务的一致性原则。


不可重读(Non-Repeatable Reads):
事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性,这个主要是针对某一行数据来说的。


幻读(Phantom Reads):
事务A读取到了事务B提交的新增数据,不符合隔离性,这个主要是针对于某一张表来说的。

1.4、事务隔离级别

Mysql默认是可重复读,下面是四种隔离级别分别可解决的并发问题。
注意:在可重复读隔离级别验证幻读的时候,可以直接更新刚才其它客户端新增的那条数据,更新完之后再查询就可以查到了。

在这里插入图片描述

-- 查看当前数据库的事务隔离级别
show variables like 'tx_isolation';
-- 设置事务隔离级别
set tx_isolation='REPEATABLE-READ';
set tx_isolation='read-uncommitted';
set tx_isolation='read-committed';
set tx_isolation='repeatable-read';
set tx_isolation='serializable';

2、锁

2.1、锁分类

1、从性能上分为乐观锁(用版本对比来实现)和悲观锁
2、从对数据库操作的类型分,分为读锁写锁
3、从对数据操作的粒度分,分为表锁行锁
4、间隙锁、临键锁 。

2.2、锁详解

2.2.1、乐观锁

乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。通过CAS版本控制来判断数据是否可以更新。

2.2.2、悲观锁

悲观锁与乐观锁刚好相反,认为每一次操作数据时都会有冲突,所以就给数据加上一把锁,表示同一时间只能有一个事务对一行数据进行操作。

2.2.3、读锁

对于同一个数据,读读不互斥,读写互斥,写写互斥。

2.2.4、写锁

同一时间只能有一个事务对一行数据进行操作。

2.2.5、表锁

一次对一整张表进行加锁,锁的粒度大,发生锁冲突的概率高,开销小,加锁快,通常用在对于表的数据迁移场景中。

-- 手动增加表锁
lock table 表名称 read(write),表名称2 read(write);
-- 查看表上加过的锁,In_use这一列数据为1则代表加上了锁
show open tables;
-- 删除表锁
unlock tables;	

加读锁时:当前session和其他session都可以读该表,当前session中插入或者更新锁定的表都会报错,其他session插入或更新则会等待。
加写锁时:当前session对该表的增删改查都没有问题,其他session对该表的所有操作被阻塞。

2.2.6、行锁

对一张表的某一行进行加锁,锁的粒度小,发生锁冲突的概率低,开销大,加锁慢。
对于Myisam:在执行查询语句SELECT前,会自动给涉及的所有表加读锁,在执行update、insert、delete操作会自 动给涉及的表加写锁。
对于InnoDB:在执行查询语句SELECT时(非串行隔离级别),不会加锁。但是update、insert、delete操作会加行锁。
总结:读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞。

2.2.7、间隙锁

比如说我们下面这张表的数据,它的区间就有 (4,10),(10,20),(20,正无穷 ) 这三个区间。

在这里插入图片描述

如果我们在可重复读隔离级别下执行下面这条sql语句,5和15分别在 (4,10)和(10,20)区间,所以通过间隙锁就锁住了4到20,不包含4和20,间隙锁是在可重复读隔离级别下才会生效。

update user set name = '1234' where id > 5 and id < 15;

如下所示:

在这里插入图片描述

在这里插入图片描述

2.2.8、临键锁(Next-key Locks)

Next-Key Locks是行锁与间隙锁的组合。相当于在上面的例子中 (4,20) 的这个开区间,加上了20这条记录。变成了 (4,20] 。

2.3、无索引行锁会升级为表锁

如果说我们去更新一条sql,这条sql的where条件没有加索引,那么这条sql会将整张表都加锁。

2.4、行锁分析

行锁也可以通过在sql语句后加上for update来加锁,不过这种容易产生死锁,一般不建议使用。
我们通过下面这条sql就可以看一看sql目前的情况:

show status like 'innodb_row_lock%';

在这里插入图片描述

属性含义
Innodb_row_lock_current_waits当前正在等待锁定的数量
Innodb_row_lock_time从系统启动到现在锁定总时间长度
Innodb_row_lock_time_avg每次等待所花平均时间
Innodb_row_lock_time_max从系统启动到现在等待最长的一次所花时间
Innodb_row_lock_waits系统启动后到现在总共等待的次数

2.5、锁优化

1、尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
2、合理设计索引,尽量缩小锁的范围.。
3、尽可能减少检索条件范围,避免间隙锁。
4、尽量控制事务大小,减少锁定资源量和时间长度,涉及事务加锁的sql尽量放在事务最后执行。
5、尽可能低级别事务隔离。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值