MySQL逻辑架构、锁、事务、MVCC

MySQL逻辑架构

在这里插入图片描述

数据库的工作流程

工作流程

从MySQL的三个层面介绍数据库的工作流程:

  • 最上层:客户端连接
    1. 连接处理:客户端同数据库服务层建立TCP连接,连接管理模块会建立连接,并请求一个线程。如果线程池中有空闲的连接线程,则分配给这个连接,如果没有,在没有超过最大连接数的情况下,创建新的连接线程负责这个客户端
    2. 授权认证:在真正的操作之前,还需要调用用户模块进行授权检查,来验证用户是否有权限。通过后,方才提供服务,连接线程开始接收并处理来自客户端的SQL语句
  • 第二层:核心服务
    1. 连接线程接收到SQL语句后,将语句交给SQL语句解析模块进行语法分析和语义分析
    2. 如果是一个查询语句,则先查询缓存中是否有结果,如果有结果之间返回给客户端
    3. 如果查询缓存没有结果,则查询数据库引擎层了,于是发给SQL优化器,进行查询的优化。如果是表变更,则分别交给insert、update、delete、alter处理模块进行处理。
  • 第三层:数据库引擎层
    1. 打开表,如果需要的话获得相应的锁
    2. 先查询缓存页中有没有相应的数据,有则直接返回,没有则从磁盘中读取
    3. 当在磁盘中找到相应的数据之后,则会加载到缓存中来,从而使得后面的查询更加高效,由于内存有限,多采用变通的LRU表来管理缓存页,保证缓存的都是经常访问的数据。
      最后,获取数据后返回给客户端,关闭连接,释放连接线程。

数据库锁

锁粒度

一种提高共享资源并发性的方式就是让锁定对象更有选择性,任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要相互之间不发生冲突即可。

所谓锁策略,就是在锁的开销和数据安全性之间寻求平衡,这种平衡当然也会影响到性能。大多数据库系统一般都是在表上施加行级锁

表锁

表锁是MySQL中最基本的锁策略,并且是开销最小的策略。它会锁定整张表。

一个用户在对表进行写操作前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。只有没有写锁时,其他读取的用户才能获取读锁,读锁之间是不互相阻塞的。

行级锁

行级锁可以最大程度地支持并发处理(同时也带来了最大地锁开销),行级锁旨在存储引擎层实现,而MySQL服务层没有实现。

死锁

死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。

当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。多个事务同时锁定同一个资源时,也会产生死锁。

死锁会导致出现非常慢的查询。InnoDB目前处理死锁的方法时,将持有最少行级排他锁(写锁)的事务进行回滚,即写操作最少的事务回滚。

事务

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。

ACID

  • 原子性(Atomicity):一个事务必须被视为一个不可分割的最小工作单元
  • 一致性(Consistency):数据库总是从一个一致性的状态转换到另一个一致性的状态
  • 隔离性(Isolation):一个事务所做的修改在最终提交之前,对其他事务是不可见的
  • 持久性(Durability):一旦事务提交,则其所做的修改就会永久保存到数据库中

事务的隔离级别

  • Read_Uncommitted(未提交读):事务可以读取未提交的数据,这也称为脏读(Dirty Read)。实际应用中一般很少用
  • Read_Committed(提交读):大多数数据库系统的默认隔离级别是提交读(但MySQL不是)。这个级别有时候也叫不可重复读,因为两次执行同样的查询,可能会得到不一样的结果
  • Repeatable_Read(可重复读):解决了脏读的问题,但理论上,可重复读无法解决幻读的问题,可重复读是MySQL的默认事务隔离级别
  • Serializable(可串行化):是最高的隔离级别,它通过强制事务串行执行,避免了幻读问题。会在读取的每一行数据上都加锁,可能会导致大量的超时和锁争用问题。实际应用中也很少用。

脏读:事务读取到了未提交的数据
不可重复度:执行两次相同的查询却得到了不一样的结果
幻读:某个事务在读取某个范围的数据时,另一个事务在范围中插入了一条数据,而之前的事务再次读取该范围时多了一条记录,即产生了幻行

隔离级别脏读可能性不可重复读可能性幻读可能性加锁读
Read_Uncommittedyesyesyesno
Read_Committednoyesyesno
Repeatable_Readnonoyesno
Serializablenononoyes

多版本并发控制(MVCC)

MySQL的大多数事务性存储引擎实现的都不是简单的行级锁,基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)

可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。大都实现了非阻塞的读操作,写操作也只锁定必要的行。

MVCC的实现是通过保存数据在某个时间点的快照来实现的。

不同存储引擎的MVCC的实现是不同的,可分为乐观并发控制和悲观并发控制。通过InnoDB的简化版来说明MVCC的工作流程

InnoDB的MVCC

InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,一个保存了行的创建时间,一个保存了行的过期时间(或删除时间)。存储的并不是实际的时间,而是系统版本号。

每开始一个新事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来查询到的每行记录的版本号进行比较。

在Repeatable_Read隔离级别下,MVCC的具体操作:

  • Select:
    InnoDB会根据以下两个条件检查每行记录:
    • InnoDb只查找版本号早于当前事务版本的数据行(行的版本号 <= 事务的版本号),这样可以确保事务读取的行,要么是在事务开始前已存在的,要么是事务自身插入或修改过的。
    • 行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行在事务开始之前未被删除。
  • Insert:
    • InnoDB为新插入的每一行保存当前系统版本号作为行版本号
  • Delete:
    • InnoDB为删除的每一行保存当前系统版本号作为行删除标识
  • Update:InnoDB为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号作为行删除标识。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值