mysql 事务锁机制

事务ACID 属性;

1).原子性(Atomicity):就是在执行SQL语句开启事务的时候要不全部执行,要不不执行
2).一致性(Consistent):事务的开启到结束,数据必须保持一致状态;
3).隔离性(lsolation): 事务不受外界并发的影响,也不受环境影响;
4). 永久性(durable):一但事务完成他对修改的数据是永久的,不会因为其他问题而丢失;
并发事务带来的问题
更新丢失(或者脏写)
当两个或者多个事务对同一行数据进行修改的时候由于隔离性,我并不知道其他的事务就会出现数据的丢失,最后结束的事务会覆盖掉其他事务的更新操作
脏读
假如我们现在有两个事务同时开启;1事务做查询,2事务做修改,当2事务完成修改但是没有提交事务,这时候1事务却读取了2事务修改后的数据;事务1读取了事务2更新没有提交的数据违背了一致性;
不可重复读
在同一个事务中当第一次查询到数据与第二次查询的数据不一致是;违背了隔离性
幻读
事务1读取到了事务2的提交数据(前提是在事务2提交之前事务1以开启);

事务隔离级别

脏读,不可重复读,幻读都是数据库解决一致性和隔离性问题
在这里插入图片描述
数据库事务的隔离级别越高我们的并发能力就越低,因为它是把并发改成串行执行;
查看mysql当前的事务隔离级别 :show variables like 'transaction_isolation’
设置隔离级别:set transaction_isolation= 'REPEATABLE-READ’
mysql的默认隔离级别就是可重复读,在开发中我们可以指定隔离级别不指定就是默认的可重复读

锁机制

锁是计算机多进程和并发访问同一资源的机制;
锁分类
1).从性能上说有乐观锁(通过版本号验证来实现)悲观锁
2).从数据操作上分读锁写锁
读锁:属于共享锁就是多个查询同时进行互不影响;写锁: 排它锁当前的写没有完成,它阻塞其他的读锁和写锁
3).从细粒度上分表锁行锁
表锁
每次操作都会给整张表加锁;优点:加锁快,开销小;不会出现死锁; 缺点: 锁粒度大,易发生冲突,并发低 一般使用在数据库迁移
创建一个操作数据表

--建表
 CREATE TABLE `mylock` (
`id` INT (11) NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR (20) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE = MyISAM DEFAULT CHARSET = utf8;

--插入数据
 INSERT INTO `mylock` (`id`, `NAME`) VALUES ('1', 'a');
 INSERT INTO`mylock` (`id`, `NAME`) VALUES ('2', 'b');
 INSERT INTO`mylock` (`id`, `NAME`) VALUES ('3', 'c');
INSERT INTO`mylock` (`id`, `NAME`) VALUES ('4', 'd');

从上面的语句中我们知道此表为MyISAM 引擎,我们大概知道MyISAM是不支持事务的,所以在并发中我们添加数据或者修改就会出现修改覆盖修改这种情况,从而有一个修改不会成功;为了解决这种情况我们可以通过加锁的方式,一般MyISAM 中可以自动上锁;
手动上锁: lock table 表名称 read(write),表名称2 read(write); 查看上锁的表: show open tables; 删除表上的锁: unlock tables;
上读锁
在这里插入图片描述
在当前的session 中创建一个表的读锁后当前使用修改会报错,其他的session 只能查询如果出现修改则会出现死锁;
上写锁
在这里插入图片描述
在当前的session 可以进行增删改查,如果不释放锁其他的session 中不能进行操作
案例结论: 当在我们的MyISAM 引擎中添加了读锁,则只能在当前session 或者其他session 中使用读而不能进行写,只有释放后才可以写;
当添加的是写锁则会阻塞所有的读写操作,只有当前的可以进行读写,只有释放锁其他的才可以

行锁
每次操作锁住一行数据;**缺点:**开销大,加锁慢,会出现死锁;**优点:**锁定力度小,不易发生锁冲突,并发高;
Innodb和MyISAM 的区别
Innodb 支持事务(Transaction)
Innodb 支持行锁
行锁演示
找一个使用innodb引擎的表就可以我这边我是用我数据库中account ;
我在我的第一个客服端中开启一个事务,当我跟新一个数没有提交如下

在这里插入图片描述
在这里插入图片描述
这个就是一个session 跟新一个数据没有提交,另一个session 更新同一数据他会等待上一个session 删除锁以后才能跟新,如果一直没有删除锁那么它会在一段时间后过期;

总结
在MyISAM 中在select之前 会给涉及的所有表加上读锁,在使用update,insert, delete 会对表上,上写锁;
在Innodb 中在select (在非串行的时候不会上锁),再有在update ,insert ,delete 会加上行锁;

分析事务隔离级别

读未提交
把mysql 的事务隔离级别设置成read uncommitted;set transaction_isolation='read-uncommitted’
(1).客户端1开启事务如下
在这里插入图片描述
(2).客户端2设置隔离级别开启事务;
在这里插入图片描述
(3).客户端1修改money字段;
在这里插入图片描述
(4).客户端2查询到了未提交的数据
在这里插入图片描述
这样的数据就出现了脏读 也违反了一致性
读已提交
(1).客户端1设置读已提交 read committed;查询account ;
在这里插入图片描述
(2).客户端2 设置修改并提交事务;

在这里插入图片描述
(3)再次查询客户端1 出现两次的查询结果不一样,这样就是不可重复读的问题
在这里插入图片描述
可重复读——mysql 默认就是可重复读
(1).打开客户端1开启事务 查询account表 的数据
在这里插入图片描述
(2).客户端2 开启事务修改id=1修改money-100;
在这里插入图片描述
(3)客户端1 在查询一下数据 没有出现脏读
在这里插入图片描述
(4).把客户端2修改的数据提交再去查询客户端1的数据我们发现还是一样的;说明也没出现不可重复读
在这里插入图片描述
验证一下幻读
(1).上面的客户端一还没有提交,现在重新开一个客户端然后呢向数据库去添加一个数据;
在这里插入图片描述
(2).在客户端一中修改这个刚插入,实际现在是查不出来刚插入的值;

在这里插入图片描述
幻读出了绿色部分的数据;
可串行化
这个我就简单阐述一下基本用不到,当我们的客户端1 设置了串行,开启事务并且查询account 中所有的数据;在这里插入图片描述
客户端2 设置串行并添加数据
在这里插入图片描述
可以看到当1不提交二是不可以插入数据也就是当我查询所有的值的时候他进行,行锁,不仅锁住了[1,5]还锁住了(5,正无穷);这样就避免了幻读但是这种方式也是极其损耗新能的,这种情况进类似与表锁;但是这是中特殊的情况假设我们现在查询的值是id>4那么他就会对(4,正无穷)加锁;
间隙锁
间隙锁,锁的就是两个值之间的空隙。Mysql默认级别是repeatable-read,有办法解决幻读问题吗?间隙锁
在某些情况下可以解决幻读问题

无索引行锁会升级为表锁
锁主要是加在索引上,如果对非索引字段更新,行锁可能会变表锁
session1 执行:update account set money= 800 where name = ‘haha’;
session2 对该表任一行操作都会阻塞住
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为
表锁。
锁定某一行还可以用lock in share mode(共享锁) 和for update(排它锁),例如:select * from
test_innodb_lock where a = 2 for update; 这样其他session只能读这行数据,修改则会被阻塞,直到锁定
行的session提交
结论
Innodb存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面所带来的性能损耗可能比表级锁定会要更
高一下,但是在整体并发处理能力方面要远远优于MYISAM的表级锁定的。当系统并发量高的时候,Innodb
的整体性能和MYISAM相比就会有比较明显的优势了。
但是,Innodb的行级锁定同样也有其脆弱的一面,当我们使用不当的时候,可能会让Innodb的整体性能表现
不仅不能比MYISAM高,甚至可能会更差。

行锁分析
通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况

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:系统启动后到现在总共等待的次数
对于这5个状态变量,比较重要的主要是:
Innodb_row_lock_time_avg (等待平均时长)
Innodb_row_lock_waits (等待总次数)
Innodb_row_lock_time(等待总时长)

尤其是当等待次数很高,而且每次等待时长也不小的时候,我们就需要分析系统中为什么会有如此多的等待,
然后根据分析结果着手制定优化计划。
查看INFORMATION_SCHEMA系统库锁相关数据表

--查看事务
select * from INFORMATION_SCHEMA.INNODB_TRX;
-- 查看锁
 select * from INFORMATION_SCHEMA.INNODB_LOCKS;
--查看锁等待
select * from INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
-- 释放锁,trx_mysql_thread_id可以从INNODB_TRX表里查看到
kill trx_mysql_thread_id

-- 查看锁等待详细信息
show engine innodb status\G;

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值