【mysql-3】mysql事务和锁

一:事务控制演进

我们知道,mysql 事务有ACID特性。 在多事务并发时候,会出现一系列问题: 脏读,幻读,不可重复读等问题。 那么,针对事务的控制,mysql经历以下几种演进

  • 排他锁(互斥锁): 读写都加锁
  • 读写锁:读和读不互斥,其他互斥: 读不加锁,写加锁
  • MVCC多版本控制:写和写互斥,其他不互斥,在RC和RR两种隔离级别下起作用。
    • 原理:读不加锁,写加锁。 但是写的时候,会将修改前的记录保存快照版本,在commit前,其他事务读取快照版本。
    • 示例:假如现在新插入一条数据如下(前面为数据,后面分别为:隐藏行id,当前正在操作数据的事务id,当前事务指向的回滚版本)
    • 事务1修改数据锁定该行,记录redo log;拷贝上面数据为快照记录到undo log;  修改当前值,填写事务编号,回滚指针指向undo log中修改前的行。
    • 事务2也修改(如果事务1还未提交释放锁,那就只能先等待),过程如上

如上,undo log中便会存在多个快照版本,这多个快照版本可能都在被其他读事务使用(新来的读事务会读最近一次快照版)。 此外,后台purge线程会定期清除没有活跃事务操作的早期快照版本。

  • MVCC已经实现了读读、读写、写读并发处理,如果想进一步解决写写冲突,可以采用两种方案:
    • 乐观锁      悲观锁

二: 事务隔离级别

基于上述演进的解决方式,mysql实际体现是通过事务隔离级别:

  • Read Uncommitted 读未提交:可能发生脏读现象
  • Read Committed 读已提交:可能发生不可重复读现象,一个事务多次读取过程中,别的事务修改并提交了数据。
  • Repeatable Read(默认) 可重复读:可能发生幻读, 一个事务多次读取的过程中,别的事务插入或删除了数据。
  • Serializable 串行化:所有的增删改查串行执行。它通过强制事务排序,解决相互冲突,这个级别可能导致大量的超时现象的和锁竞争,效率低下。

三:锁机制和实战

事务隔离级别的实现,就是通过底层锁机制 + log(redo log 和 undo log)实现。 有表锁和行锁,下面来看看innodb引擎下的行锁机制:

行锁原理:

  • 行锁是通过对索引页的记录加锁实现,有3种算法:
  • RecordLock: 锁定单个索引行记录(记录锁,在RC, RR级别下都支持)
  • GapLock: 锁定索引行之间的间隙(范围锁,RR下支持)
  • Next-key Lock: 前两种组合,同时锁住索引记录,以及相邻索引之间的间隙(记录+范围锁,RR下支持)

mysql的默认隔离级别是RR,InnoDB对于操作记录的加锁,都是先使用Next-key Lock,如果当前sql有唯一索引,则降级为RecordLock。 下面看看几种sql下的情况:

  • select ... from 语句: 普通的查询语句,采用MVCC机制实现非阻塞读,不加锁。
  • select ... from lock in share mode语句: 使用Next-Key Lock锁住相关索引记录及之间的间隙,如果扫描发现唯一索引,降级为RecordLock。
  • select ... from for update语句:追加了排他锁,InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,降级为RecordLock
  • update ... where 语句:InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,可以降级为RecordLock锁。
  • delete ... where 语句:InnoDB会使用Next-Key Lock锁进行处理,如果扫描发现唯一索引,可以降级为RecordLock锁。
  • insert语句:InnoDB会在将要插入的那一行设置一个排他的RecordLock锁。

 

下面看一下实际例子:update t1 set name=‘XX’ where id=10

如果id是主键: 主键加锁, 在主键的索引树上,锁住10这一行记录(主键索引是覆盖索引,也包含了其他data数据)

 

如果id是唯一索引,name才是主键: 先在id的二级索引树上加锁,通过id找到主键name,再到主键索引树上加锁

 

name是主键,id是非唯一索引:先在二级索引树上加锁,再到主键索引树加锁

 

如果id没有索引:不能确定操作哪一条索引,那么所有的索引和间隙都会被上锁,也就是表锁(这也是我们强调要尽量创建索引的原因)

悲观锁和乐观锁,这里就不再说了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值