mysql事务原理-锁机制

锁机制:

保证事务的隔离性

1.行级锁

每次操作锁住对应行的数据。锁定粒度(范围)最小,发生锁冲突的概率最低,并发度最高,缺点就是锁的开销比较大,加锁比较慢,容易出现死锁情况。同时对同一条记录加上不兼容的锁,Innodb并不能完全自动检测到死锁,这需要通过设置锁等待超时参数 innodb_lock_wait_timeout 来解决。

在InnoDB存储引擎中,索引结构中聚集索引的叶子结点存储的是行数据,而二级索引的叶子结点存储的是主键,所以INNODB的数据是基于索引组织的,行级锁是对索引上的索引项加锁的,而不是对记录加锁

**行锁(Record Lcok)😗*锁定单行的记录,数据库表中有一个主键索引和一个普通索引,根据这两个索引就可以锁定该记录,在RC,RR隔离级别下都支持。分为共享锁s和排它锁x

共享锁:允许读该记录,
排他锁:允许更新该记录
共享锁和共享锁之间兼容,共享锁和排他锁之间不兼容,排它锁和排它锁也不兼容

一,如果你的sql语句是根据索引进行检索的,也就是你的检索条件已经建立了索引,那么会对对应的记录加上行锁,比方说检索条件为主键id。
1.在执行select语句时,如果没有手动加共享锁,就没有任何锁,手动加上lock in share mode,这样就加上了共享锁。
如果当前客户端开启事务对该记录加上了共享锁,其他客户端执行事务对该记录查询时也可以加上共享锁,共享锁兼容,两个事务都能查询到该记录。

2.在执行insert,update,delete语句,该记录行会自动加上排它锁。
如果当前客户端开启事务执行select语句会对该记录加上共享锁,其他客户端开启事务要去执行update等语句,但是发现该记录有了共享锁,共享锁和排它锁不兼容,所以命令进入阻塞状态。对应提交事务就会释放对应事务当中加的锁。
如果当前客户端开启事务执行update等语句会对该记录加上排它锁,其他客户端开启事务也要去执行update等语句,但是该记录已经加上了排它锁,排它锁和排它锁不兼容,所以命令进入阻塞状态。对应提交事务就会释放对应事务当中加的锁

3.在执行select… for update语句时,for update就是对该记录加互斥锁。
#select …for update 会等待行锁释放之后,返回查询结果。

**二,如果你的sql语句不是根据索引进行检索的,也就是你这个检索条件没有建立索引,那么会对整张表加上表锁。**引发全表的扫描,多个这样的事务执行后,就很容易产生死锁和阻塞,最终应用系统会越来越慢,发生阻塞或死锁。

查看行锁的加锁情况:

select object_schema,object_name,index name,lock_type,lock_ mode,ock_ data from performance_schema.data_locks;

临键锁(Next-Key Lock)∶行锁和间隙锁组合,也即是如果当前记录加上和行锁,它前面的间隙加上了间隙锁,就称这条记录加上了临键锁。在RR隔离级别下支持。

间隙锁(Gap Lock)∶锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。间隙锁可以共存。

**一,**当前客户端开启事务执行sql:
如果你是根据唯一索引进行等值检索时(比方说update,select语句),如果没有符合条件记录,就会在该检索条件相邻两条记录之间加上间隙锁
如果其他客户端开启事务执行insert语句要对刚才间隙进行插入,由于存在间隙锁,insert命令进入阻塞状态,等待其他客户端提交事务释放间隙锁。如果执行的不是insert语句,而是(update,select语句)如果发现没有符合条件的记录,那么他也可以加上间隙锁,虽然重复但是都能使用间隙锁

二,如果你是根据普通索引(非唯一索引)进行等值检索(update和select)时,如果找到了符合条件的记录,会对该记录的前后间隙加上间隙锁向右遍历时最后一个值不满足查询需求时,临间锁退化为间隙锁

在这里插入图片描述

比方说age是非唯一索引,该索引为 6 <->12<->16<->18 <->18 <->18 <->29 <->34 <->45
那么最后一个18到29还有16到18都会加上间隙锁

三,如果使用唯一索引进行范围查询,符合条件的记录之间会插入间隙锁。

在这里插入图片描述

2.表级锁

表级锁会锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyIlSAM、InnoDB、BDB等存储引擎中。表级锁分为:表锁,元数据锁(Meta Data Lock)和意向锁三种。

表锁:分为表共享读锁(read lock)和表独占写锁(write lock)

使用命令:

#加锁:
如果加的是表共享读锁,所有的客户端只能读取该表,不能写
如果加的是表独占写锁,当前客户端可以读或写,其他客户端不能读写
lock tables tablename read/write;
#释放锁:
unlock tables /客户端断开连接。

元数据锁:当你给表加锁的时候或者执行SQL,系统会自动加上元数据锁,元数据指的就是表结构,如果某张表存在未提交的事务,那么不能修改这张表的结构,也就是为了避免DML语句和DDL语句的冲突,保证读写的正确性。mysql5.5中引入了元数据锁

元数据锁分为共享读锁,共享写锁和互斥锁,共享锁之间可以兼容,共享锁和互斥锁不兼容
执行select语句加上共享读锁(shared_read)
执行update,insert,delete语句加上的是共享写锁(shared_write)
执行alter语句加上的是互斥锁(exclusive)
所以就保证了对表中数据修改时,表的结构不能发生变化。保证数据的完整性和一致性

查看元数据锁:

select object_type,object_schema, object_name,1ock_type,1ock_duration from
performance_schema.metadata_locks ;

意向锁:

意向锁就是代替了全局扫描去检查每条记录的行锁情况,也就是表中记录加行锁没有,加的是什么行锁,共享锁还是排它锁。这个意向锁相当于暴露出当前表中记录加行锁的类型,利于直接判断当前表能不能加表锁(排他锁与排它锁不兼容,排它锁和共享锁互斥)

流程如下:

当前客户端开启事务去执行sql命令:
当你执行update语句时,自动给该表的这条记录加上行排他锁,此时还会自动给表加上意向排它锁
当你执行的是select…lock in share mode语句(普通select没有加锁),该记录会加上行共享锁,此时还会自动给表加上意向共享锁。

当另一个客户端开启事务要对该表执行加表锁命令时lock tables tablename read/write 会先检查意向锁的情况
如果没有意向锁,也就是该表记录没有任何行锁存在,可以加任何表锁(表共享读锁,表独占写锁)
如果发现是意向共享锁,可以给表加上表共享读锁。
如果发现是意向排它锁,不可以给表 加上任何锁 ,此时命令进入阻塞状态,等待其他客户端事务的提交释放行锁和意向锁。

在这里插入图片描述

查看意向锁及行锁的加锁情况:

select object_schema,object_name,index_name,lock_type,ock_mode,lock_data from performance_schema.data_locks;
3.全局锁

全局锁就是对整个数据库实例加锁,也就相当于对数据库的所有表加锁,加锁后整个实例就处于只读状态,后续的增删改事务提交的语句都将被阻塞。

使用场景:做数据库的备份,对所有的表进行锁定,保证数据的一致性和完整性。

备份流程:

#1.加锁全局锁,锁住全部表,其他客户端只能读不能改或写,更新或者插入命令进入阻塞状态
flush tables with red lock; 
#2.将数据库数据备份到sql文件中,期间数据库支持查询操作。-u后面跟用户名,-p后面跟密码
mysqldump -uroot -p1234 itcast>itcast.sql
#3.备份完毕释放锁.
unlock tables;                          

注意事项:

#>mysqldump -h192.168.200.202 -uroot -p1234 db01 >D:/db01.sql
mysqldump是mysql的工具,不是sql命令,所以不要在mysql的命令行执行,后面地址是访问的远程服务器
1.如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。
2.如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志((binlog),会导致主从延迟。

**不加锁备份:**在innodb中

#通过快照读来实现的,也就是备份时的数据,备份过程中的提交的事务时是看不到的,也不会备份进去。
#在备份时加上参数--single-transaction参数来完成不加锁的一致性数据备份。
mysqldump --single-transaction -uroot -p123456 itcast > itcast.sql

single-transaction 实际上通过做了下面两个操作 :
① 在开始的时候把该当前窗口的事务隔离级别设置成 repeatable read ;
② 然后启动一个事务(执行 begin ),备份结束的时候结束该事务(执行 commit )
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值