浅析Innodb事务底层实现原理

如果对事务的基本知识不是太了解,可以先去看这篇文章【MySQL】事务知识小结

MySQL只有innodb引擎支持事务,因此这篇文章也是以innodb为背景写的。

一、事务并发会带来什么问题?

  • 脏读:读到了其他事务未提交的数据
  • 不可重复读:当前事务先进行了一次数据读取,然后再次读取到的数据是别的事务修改成功的数据,导致两次读取到的数据不一致(update、delete)
  • 幻读:当前事务读第一次取到的数据比后来读取到数据条目少(insert)

解决上面的问题就需要设置相应的事务隔离性

  • Read Uncommitted(未提交读) :事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”。
  • READ COMMITTED (提交读):保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。
  • REPEATABLE READ(重复读) :默认隔离级别,保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但不能避免“幻读”,但是带来了更多的性能损失。
  • Serializable (串行化):最严格的级别,事务串行执行,资源消耗最大,解决了所有问题。

需要注意,在innoDB引擎中,当隔离级别为可重复读就可以解决幻读的情况,因为innodb

  • 在快照读读情况下,mysql通过mvcc来避免幻读。
  • 在当前读读情况下,mysql通过next-key来避免幻读

因此innodb的默认隔离级别就是可重复度.

二、如何实现事务隔离级别?

首先有两种方式:

  • 加锁:在读取数据前,对其加锁,防止其他事务对数据进行修改。
  • MVCC:多版本并发控制,指的是一种提高并发的技术,生成一个数据请求时间点的一致性数据快照,并用这个快照来提供一定级别的一致性读取.

最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。在内部实现中,InnoDB是在undolog中实现的,通过undolog可以找回数据的历史版本。

三、锁内容详解

1、锁的分类

1.1表锁和行锁

首先来看看表锁和行锁,顾名思义,表锁是锁住整张表,行锁是锁住一行的数据,下面是它们的区别

  • 锁定粒度:表锁>行锁
  • 加锁效率:表锁>行锁
  • 冲突概率:表锁>行锁
  • 并发性能:表锁<行锁

MyISAM存储引擎仅支持表锁;innodb存储引擎既支持行锁又支持表锁。

1.2共享锁和排他锁(行锁)

共享锁:又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同意数据可以共享一把锁,都能访问到数据,但是只能读不能修改。

共享锁的加锁释放锁方式:

BEGIN;

select * from student where id =1 LOCK INSHARE MODE;

commit/rollback;

排他锁:又称为写锁,排他锁不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事物就不能再获取该行的锁,只有该获取了排他锁的事务才能对数据进行读取和修改。

排他锁的加锁释放锁方式:

  • 自动:delete/update/insert 默认加上排他锁
  • 手动:select * from student where id = 1 FOR UPDATE;

1.3意向共享锁和意向排他锁(表锁)

首先需要知道意向锁是由数据引擎自己维护的,用户无法手动操作意向锁。

意向共享锁:表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的意向共享锁。

意向排他锁:表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的意向排他锁。

思考:为什么需要(表级别的)意向锁?

因为在加表锁时,如果此时表中已经有其他事务锁定了这张表的任一行,表锁就不能成功,因此在加表锁时会先去判断每一行有没有加锁,然后再看加不加表锁,但是判断每一行加没加锁显然效率太低了,因此就需要意向锁,使用意向锁就会在加表锁时直接判断是否有意向锁即可,提高了效率。

2、锁的作用

锁是为了解决资源竞争并发的问题,在Java中资源就是对象,在Mysql中就是数据表、数据行

3、锁到底锁住了什么?

当数据库中没有索引时,加锁会锁住整张表.

其实数据库中的锁是锁住索引项实现的!对于innodb而言,如果没有索引它定义一个主键来作为聚簇索引。那也就是在我们没有创建索引时,对innodb存储引擎而言,我们加锁表中的数据,锁住的就是这个隐式聚簇索引,InnoDB行锁对唯一索引或主键索引的数据生效,若我们没有手动的去加索引,那么对于加锁时只有sql语句能用到默认的聚簇索引也就是默认的主键索引时才会锁住行,因此我们常说如果没有建主键索引,使用innodb时会锁整张表。

4、行锁的算法

分为三种:记录锁、间隙锁、临键锁

记录锁:总是会锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时InnoDB存储引擎会使用隐式的主键来进行锁定。

间隙锁: 只在RR级别存在,是为了解决Phantom Problem(幻象/幻读),利用这种锁技术,锁定的不是单个值,而是一个范围。

临键锁: 是结合了记录锁和间隙锁的一种锁定算法,在此种算法下,InnoDB对于行的查询都是采用这种锁定算法。

 

在mysql中就是使用锁+MVCC实现事务,当只有写写时才会阻塞。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值