MySQL 学习

学习笔记   2023-12-15 11:49   1005   0  

MySQL架构

1 MySQL逻辑架构

image-20230918164436814

  1. 最上层的服务,连接和线程处理。比如连接处理、授权认证、安全等

  2. 第二层架构,MySQL的核心服务功能都在这一层,包括查询解析、分析、优化、缓存以及所有的内置函数(例如,日期,时间

  3. 第三层包含了存储引擎,服务器通过API与存储引擎进行通信,不同存储引擎之间也不会互相通信

在第二层当中,服务器会先检查缓存,如果存在就不会执行查询解析、优化和执行的整个过程

所以查询缓存是在查询解析、优化和执行之前进行的

2 并发控制(锁)

2.1 读写锁

在处理并发都或者写时,可以通过实现一个由两种类型的锁组成的锁系统来解决问题,这两种类型的锁通过被称为共享锁(shared lock)和排他锁(exclusive lock),也叫读锁(read lock)和写锁(write lock)

  • 读锁是共享的,或者说是互相不阻塞的,多个客户在同一时刻可以同时访问同一个资源,而互不干扰

  • 写锁则是排他的,也就是说一个写锁会阻塞其他的写锁和读锁

2.2 锁粒度

一种提高共享资源并发性的方式是让锁定对象各有选择性,尽量之锁定需要修改的部分数据,而不是所有数据。更理想的方式是,只对会修改的数据片进行精确的锁定。

所谓的锁策略,就是在锁的开销和数据的安全性之间寻求平衡,这种平衡也会影响到性能

大多数商业数据库系统,都是在表上施加行级锁(row-level lock)

表锁(table lock)

表锁是MySQL中最基本的锁策略,并且是开销最小的策略。一个用户在对表进行写操作的时候,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作,只有没有写锁的时候,其他读取的用户才能获得读锁,读锁之间是不互相阻塞

写锁具有比读锁更高的优先级,一个写锁请求可能会插入到读锁队列的前面

行级锁(row lock)

行级锁可以最大程度地支持并发处理,同时也带来了最大的锁开销

3 事务

事务就是一组原子性的SQL查询,事务内的语句,要么全部执行成功,要么全部执行失败

事物的ACID

  • 原子性(atomicity):事务必须被视为一个不可分割的最小工作单元,整个事务的所有操作要么全部提交成功,要么全部失败回滚

  • 一致性 (consistency):数据库总是从一个一致性的状态转换到另外一个一致性的状态。事务没有最终提交,事务中所作的修改也不会被保存到数据库中

  • 隔离性(isolation):一个事务所作的修改在被最终提交以前,对其他事务是不可见的

  • 持久性(durability):一旦事务提交,则其所作的修改就会永久保存到数据库中

3.1 隔离级别

隔离性远比想象中的复杂,在SQL表中中定义了四种隔离级别

  • READ UNCOMMITTED (未提交读):事务可以读取未提交的数据,这也被称为脏读(Dirty Read)

  • READ COMMITTED (提交读):大多数数据库系统默认的隔离级别都是READ COMMITTED(但是MySQL不是,MySQL是 REPEATABLE READ)。一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的

  • REPEATABLE READ(可重复读):该级别保证了在同一个事务中多次读取同样记录的结果是一致的。理论上可重复读无法解决幻读(Phantom Read)问题。可重复读是MySQL的默认事务隔离级别

  • SERIALIZABLE(可串行化):SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了幻读问题。简单来说,SERIALIZABLE会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用问题。实际中很少用到这个隔离级别

image-20230918171950941

3.2 死锁

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

数据库系统实现了各种死锁检测和死锁超时机制。

  • 死锁检测,比如InnoDB存储引擎,能检测到死锁的循环依赖,并立即返回一个错误

  • 死锁超时(不太好),当查询的时间达到锁等待超时的设定后放弃锁请求

目前InnoDB处理死锁的方法是,将持有最少行级排他锁的事务进行回滚

大多数情况下只需要重新执行因死锁回滚的事务即可

3.3 事务日志

事务日志是一个与数据库文件分开的文件。它存储对数据库进行的所有更改,并全部记录插入、更新、删除、提交、回退和数据库模式的变化

事务要保证ACID的完整性必须依靠事务日志做跟踪,每一个操作在真正写入数据数据库之前,先写入到日志文件中。如要删除一行数据会先在日志文件中将此行标记为删除,但是数据库中的数据文件并没有发生变化。只有在(包含多个sql语句)整个事务提交后,再把整个事务中的sql语句批量同步到磁盘上的数据库文件。

修改数据需要写两次磁盘

在事务引擎上的每一次写操作都需要执行两遍:

  1. 先写入日志文件中。

    写入日志文件中的仅仅是操作过程,而不是操作数据本身,所以速度比写数据库文件速度要快很多

  2. 然后再写入数据库文件中

    写入数据库文件的操作是重做事务日志中已提交的实务操作的记录

事务日志的好处

事务日志采用的追加的方式,因此写日志的操作是磁盘一小块区域的顺序IO,而不像随机IO需要在磁盘上多个地方移动,所以采用事务日志的方式,相对来说快很多,事务日志持久后,内存中的修改在后台慢慢刷回磁盘,期间如果系统发生崩溃,存储引擎在重启的时候依靠事务日志恢复这部分被修改的数据。

3.4 MySQL中的事务

MySQL提供了两种事务型的存储引擎:InnoDB和NDB Cluster。

自动提交(AUTOCOMMIT)

MySQL默认采用**自动提交(AUTOCOMMIT)**模式,也就是说,如果不是显示地开始一个事务,则每个查询都被当作一个事务执行提交操作

可以通过设置AUTOCOMMIT变量来启用胡总和禁用自动提交模式

set AUTOCOMMIT = 1;
# 1或者ON 表示启用,0或者OFF表示禁用

MySQL能够识别所有的4个ANSI隔离级别,InnoDB引擎也支持所有的隔离级别

可以通过命令来设置隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

隐式和显式锁定

InnoDB采用的是两阶段锁定协议(two-phase locking protocol)

隐式锁定:在事务执行过程中,所示可以执行锁定,锁只有在执行COMMIT或者ROLLBACK的时候才会解开,并且所有的锁实在同一时刻被释放

显示锁定:InnoDB支持通过特定的语句进行显示锁定

SELECT ... LOCK IN SHARE MODE
SELECT ... FOR UPDATE

MySQL也支持LOCK TABLE 和 UNLOCK TABLES语句,这是在服务器层面实现的,和存储引擎无关

4 多版本并发控制MVCC

多版本并发控制MVCC(Multiversion Concurrency Control),解决了REPEATABLE READ可重复读中存在的幻读问题,它在很多情况下避免了加锁的操作,因此开销更低。虽然实现的机制各有不同,但大都实现了 非阻塞的读操作,写操作也之锁定必要的行

InnoDB的MVVC,是通过再每行记录后面保存两个隐藏的列来实现。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。存储的并不是时间,而是系统版本号(system version number)。每开始一个新的事务,系统版本号就会递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到每行记录的版本号进行比较。

REPEATABLE READ隔离级别下,MVCC具体操作

image-20230918182238899

优点:

  • 保存两个额外的版本号,使大多数操作都可以不用加锁,使得读数据操作更加简单,性能更好,并且能够保证只会读到符合标注的行

缺点:

  • 需要额外的空间

  • 需要更多的行检查工作

  • 一些额外的维护工作

MVVC只在REPEATABLE READ 和READ COMMITED两个隔离模式下工作。READ UNCOMMITED总是读取最新的数据行,SERIALIZABLE会对读取的行都加锁



博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。