Mysql高级性能优化之锁(十三)

概念

在计算机中,协调多个进程或线程并发访问某一资源的一种机制; 在数据库中,除了传统的计算资源(I/O,CPU,RAM等),数据也是一种供许多用户共享访问的资源; 如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素。

在购买商品的时候,商品库存只有一个,两人同时购买,这个时候就涉及锁的一个概念,会用到事务,先从库存表中取出物品的数据,然后插入订单,付款后,插入付款表,更新商品信息,在这个过程中,使用锁可以对有限的资源进行保护,解决隔离和并发的矛盾。


锁分类

按操作分:

1、读锁(共享锁):
允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有(只能读取不能修改)。
2、写锁(排它锁):
一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁。

详情:
https://www.cnblogs.com/boblogsbo/p/5602122.html
https://www.cnblogs.com/panxuejun/p/8874321.html


按粒度分:

1、表锁:
偏向Myisam存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发最低(整张表只能一个人使用);

(1)示例:
①建立一张Myisam引擎的表
在这里插入图片描述
②查看表有没有被锁过:show open tables;(若1,说明表被加锁;0,为表没被加锁)
③对表加锁:lock table locktest(表名) read(读锁),locktest2 (表名) write(写锁);
④对表进行解锁:unlock tables;

(2)读写锁对操作和性能产生哪些影响
①对locktest(表名)添加读锁,lock table locktest read;

操作内容当前连接另一个连接
是否可以查看自己可以可以
是否可以更新不可以当更新时,处于阻塞状态,等待解锁后,才能进行更新
能不能读别的表当前表没有解锁的情况下,不可以可以

②对locktest(表名)添加写锁,lock table locktest write;

操作内容当前连接另一个连接
是否可以查看自己可以当更新时,处于阻塞状态,等待解锁后,才能查看
是否可以更新可以当更新时,处于阻塞状态,等待解锁后,才能进行更新
能不能读别的表当前表没有解锁的情况下,不可以可以
表锁分析
show status like ‘table(表名)%’ :查看表的状态可以查看表的创建时间
Myisam的读写调度是写优先,这也是myisam不适合做为主表的引擎
因为写锁后,其他线程不能做任何操作,大量更新会使用查询很难得到锁,从而造成永久阻塞

商城可分为两个库,卖家库和买家库,卖家库更偏向于写,买家库更偏向于读

若表经常做一些更新操作,就不要使用表锁;若读数据比较多的时候,可以使用表锁。


2、行锁:
偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度小,发生锁冲突的概念最高,并发度也高;
(1)事务
ACID属性说明
原子性事务包含的所有操作要么全部成功,要么全部失败回滚
一致性事务执行之前和执行之后都必须处于一致性状态,让数据保持一定上的合理
隔离性当多个用户并发访问数据库时,如操作同一表,数据库为每一个用户开启的事务,不能被其他事务所干扰,多个并发事务之间要相互隔离
持久性指一个事务一旦被提交,就不能再回滚了,已经把数据保存在数据库中了
(2)并发事务处理带来的问题
问题说明
更新丢失两个或多个事物选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生更新丢失的问题,最后的更新覆盖了其他事务做的更新
脏读事务A读到了事务B已修改,但未提交的数据(Read committed:读提交,能解决脏读的问题)
不可重复读一个事务范围内两个相同的查询却返回了不同数据,事务A读到了事务B已经提交的修改数据(Repeatable read)
重复读事务开启,不允许其他事务的UPDATE修改操作
幻读一个事务(同一个read view)在前后两次查询同一范围的时候,后一次查询看到了前一次查询没有看到的行(serializable:效率低下,比较耗数据库性能,一般不使用)
对应关系在这里插入图片描述

数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable

脏读幻读等详情:https://www.cnblogs.com/balfish/p/8298296.html

查看隔离级别语句
查看当前会话隔离级别select @@tx_isolation;
查看系统当前隔离级别select @@global.tx_isolation;
设置隔离级别
全局set global transaction isolation level repeatable read;
当前会话set session transaction isolatin level repeatable read;

在这里插入图片描述
注意:索引失效,行锁变表锁

间隙锁:https://blog.csdn.net/zcl_love_wx/article/details/82382582

如何锁定一行数据:查询语句+for update;

查看行锁的状态:show status like ‘innodb_row_lock%’;
在这里插入图片描述


3、悲观锁
对于数据被外界修改持保守态度,认为数据随时都会被修改,所以整个数据处理中需要将数据加锁, 关系数据库的行锁,表锁不论是读写锁,都是悲观锁(一般都是依靠关系型数据库提供的锁机制);
4、乐观锁
每次自己操作数据的时候认为没有人会去修改,所以不去加锁; 但是在更新的时候会去判断在此期间数据有没有被修改,需要用户自己去实现; 不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性;
为什么要使用乐观锁? 对于读操作远多于写操作的时候,大多数都是读取,这时候一个更新操作会阻塞所有读取,降低了吞吐量。 最后还要释放锁,锁是会损耗性能的,我们只要想办法解决少量的的更新操作的同步问题。 如果读写比例差距不是很大或者你的系统没有响应不及时,吞吐量瓶颈问题,那就不要去使用乐观锁,他增加了复杂度,也带来了额外的风险。
乐观锁的实现方式

在这里插入图片描述
更新操作时,查询数据把版本号或时间戳查询出来,更新语句将版本号+1或时间戳=当前时间戳,并且where条件中放入之前查询得到的版本号或时间戳,如下:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值