锁和表锁及MVCC

MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类

全局锁

命令是 Flush tables with read lock (FTWRL)

全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都 select 出来存成文本。

表级锁

表锁的语法是 lock tables … read/write

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。

死锁和死锁检测

一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。

另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

怎么解决由这种热点行更新导致的性能问题呢?
问题的症结在于,死锁检测要耗费大量的 CPU 资源。

一种头痛医头的方法,就是如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。

另一个思路是控制并发度

MVCC

在 MySQL 里,有两个“视图”的概念:

一个是 view。它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是 create view … ,而它的查询方法与表一样。

另一个是 InnoDB 在实现 MVCC 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。

“快照”在 MVCC 里是怎么工作的?

InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。

而每行数据也都是有多个版本的。每次事务更新数据的时候,都会生成一个新的数据版本,并且把 transaction id 赋值给这个数据版本的事务 ID,记为 row trx_id。同时,旧的数据版本要保留,并且在新的数据版本中,能够有信息可以直接拿到它。

也就是说,数据表中的一行记录,其实可能有多个版本 (row),每个版本有自己的 row trx_id。

请添加图片描述
1、如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;

2、如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;

3、如果落在黄色部分,那就包括两种情况a. 若 row trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见;b. 若 row trx_id 不在数组中,表示这个版本是已经提交了的事务生成的,可见。

InnoDB 利用了“所有数据都有多个版本”的这个特性,实现了“秒级创建快照”的能力。

一个数据版本,对于一个事务视图来说,除了自己的更新总是可见以外,有三种情况:

1、版本未提交,不可见;

2、版本已提交,但是是在视图创建后提交的,不可见;

3、版本已提交,而且是在视图创建前提交的,可见。

更新逻辑

更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)

事务的可重复读的能力是怎么实现的?

可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。

而读提交的逻辑和可重复读的逻辑类似,它们最主要的区别是:

1、在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;

2、在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。

### 行的概念及其区别 #### 概念定义 **行(Row-Level Locking)** 是一种细粒度的机制,它仅定数据库中被访问或修改的具体数据行。这意味着在同一时刻,多个事务可以并发地操作同一张中的不同行,互不干扰[^1]。 **(Table-Level Locking)** 则是粗粒度的机制,它在事务对进行读写时会定整张,阻止其他事务对这张的任何访问或修改,直到当前事务释放为止[^1]。 --- #### 原理对比 - **行原理** 在 MySQL 的 InnoDB 存储引擎中,行是通过索引项加实现的,主要包括以下几种类型: - **记录(Record Lock)**:定特定的索引记录。 - **间隙(Gap Lock)**:定索引记录之间的“间隙”,用于防止幻读。 - **临键(Next-Key Lock)**:结合记录间隙,既定记录本身也定其前后的间隙,确保范围查询的隔离性[^2]。 - **原理** 是对整个施加,通常由数据库管理系统在执行某些 DDL(如 `ALTER TABLE`)或全扫描的 DML 操作时自动获取。由于其定粒度大,容易造成并发阻塞,因此适用于低并发、批量处理的场景[^1]。 --- #### 区别分析 | 对比维度 | 行 | | |----------------|--------------------------------------------|------------------------------------------| | **定范围** | 定单行数据 | 定整张 | | **并发性能** | 高,并发能力强 | 低,易引发阻塞 | | **开销** | 开销较大,管理复杂 | 开销小,管理简单 | | **适用场景** | OLTP系统、高并发、精细控制 | 批量导入导出、低并发任务 | | **死风险** | 较高,需依赖事务回滚机制 | 几乎无死风险 | --- #### 应用场景对比 - **行应用场景** 行适用于需要高并发处理、事务只涉及少量数据更新的场景。例如,在银行交易系统中,用户频繁进行账户余额的增减操作,使用行可以保证多个用户同时操作不同账户时的数据一致性与并发性能[^2]。 ```sql BEGIN; SELECT * FROM accounts WHERE user_id = 100 FOR UPDATE; -- 行生效 UPDATE accounts SET balance = balance - 100 WHERE user_id = 100; COMMIT; ``` - **应用场景** 更适合于数据操作频率较低、且需要对整张进行大规模更新或结构变更的场景。例如,数据仓库中每日的批量数据加载操作通常会使用来避免并发冲突[^1]。 --- #### 数据库引擎支持情况 不同的数据库引擎对行的支持有所不同: - **MySQL InnoDB**:全面支持行级,并通过 MVCC 实现高效的并发控制;同时也支持,但优先使用行以提升并发性能。 - **Oracle**:默认使用行级机制,并结合多版本并发控制(MVCC),有效减少争用问题。 - **MyISAM(MySQL)**:仅支持,不支持行,因此不适合高并发的 OLTP 场景。 InnoDB 还可以通过间隙(Gap Lock)来防止幻读现象的发生,而无需将行升级为,从而保持较高的并发性能[^3]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值