当前位置:   article > 正文

MySQL的事务和锁_数据库一个执行查询一个执行修改会锁表嘛

数据库一个执行查询一个执行修改会锁表嘛

一. ACID特性

在关系型数据库管理系统中,一个逻辑工作单元要成为事务,必须满足这 4 个特性,即所谓的 ACID
原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持久性( Durability )。

1.1 原子性

指事务的操作是原子性的, 要么修改成功, 要么失败!
a. 事务提交了,如果此时 Buffer Pool 的脏页没有刷盘,如何保证修改的数据生效? Redo
b. 如果事务没提交,但是 Buffer Pool 的脏页刷盘了,如何保证不该存在的数据撤销? Undo
每一个写事务都会修改Buffer Pool, 从而产生Redo和Undo操作, 如果BP中脏页数据还没有刷盘成功, 这时候数据库断了,Redo会帮我们保存未刷盘的脏页, 待下次启动时刷盘, 如果以及刷盘成功, 要进行回滚, 可以通过Undo进行回滚。

2.2 持久性

持久性:指的是一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,后续的操作或故障不应该对其有任何影响,不会丢失。
一个 “ 提交 ” 触发的操作:
首先存储binlog日志 ( 如果是主从进行binlog发送) ==> 存储引擎提交 ===> 把log缓存刷盘 ==> 检查指针 ==> 事务提交标记
通过原子性可以保证逻辑上的持久性,通过存储引擎的数据刷盘可以保证物理上的持
久性。

2.3 隔离性

隔离性是InnoDB, 对数据库约束一致性和数据一致性的保障, 其由MVCC和锁来完成的!
分为读未提交、读提交、可重复读、可串行化。

2.4 一致性

约束一致性:创建表结构时所指定的外键、 Check 、唯一索引等约束,可惜在 MySQL 中不支持
Check
数据一致性:是一个综合性的规定,因为它是由原子性、持久性、隔离性共同保证的结果,而不是
单单依赖于某一种技术。
一致性也可以理解为数据的完整性。数据的完整性是通过原子性、隔离性、持久性来保证的,而这3个特性又是通过 Redo/Undo 来保证的。逻辑上的一致性,包括唯一索引、外键约束、 check 约束,这属于业务逻辑范畴。
总结: 这四个特性, 有三个都需要遵循 WAL,因为他们都需要Redo/Undo来保障, 所以必须先写日志, 后刷盘

二. 事务控制的演进

2.1 并发事务

事务并发处理可能会带来一些问题,比如:
1. 更新丢失、 指俩个事务同时操作一条记录, 回滚或者提交, 使其数据被覆盖
2. 脏读、        一个事务读到另外一个事务没有提交的修改数据
3. 不可重复读、一个事务多次读取同一条数据不一致
4. 幻读、         一个事务中多次按相同条件查询,结果不一致。

2.2 排队 ===>  排他锁   ===>   读写锁

2.3 MVCC

遵循先复制一份保存, 在进行修改, 保证了, 读读、读写、写读可以并行!
MVCC被称为 多版本控制, 指在数据库中高并发场景下, 对数据进行多版本处理, 并通过事务的可见性来保证事务看到自己应该看到的数据版本。 多版本控制很巧妙地将稀缺资源的独占互斥转换为并发,大大提高了数据库的吞吐量及读写性能。
如何生成的多版本?
每次事务修改操作之前,都会 Undo 日志中记录修改之前的数据状态和事务号,该备份记录可以用于其他事务的读取,也可以进行必要时的数据回滚。

实现原理: 

MVCC 最大的好处是读不加锁,读写不冲突。在读多写少的系统应用中,读写不冲突是非常重要的,极大的提升系统的并发性能,这也是为什么现阶段几乎所有的关系型数据库都支持 MVCC 原因,不过目前MVCC 只在 Read Commited Repeatable Read 两种隔离级别下工作。
在MVCC并发控制中, 读操作分为: 快照读和当前读
a. 快照读:读取的是记录的快照版本(有可能是历史版本),不用加锁。( select
b. 当前读:读取的是记录的最新版本,并且当前读返回的记录,都会加锁,保证其他事务不会再并发修改这条记录。(select... for update lock in share mode insert/delete/update
流程: 每个表中字段后面都隐藏了三个字段: 隐含ID(没有索引时触发), 事务ID, 回滚指针
1. 当进行更新操作时: 用排他锁锁定该行;记录 Redo log ;根据ROW_ID 保存一份到Undo中;修改当前值,填写事务编号, 使用回滚指针指向Undo
2. 事务二修改时, 重复操作, 利用回滚指针指向事务一, 最后Undo日志中越来越的的日志会由 Purge Thread线程进行销毁

三. 事务的隔离级别

3.1 隔离级别类型

A. 读未提交

Read Uncommitted 读未提交:解决了回滚覆盖类型的更新丢失,但可能发生脏读现象,也就是
可能读取到其他会话中未提交事务修改的数据。

B. 已提交读

Read Committed 读已提交:只能读取到其他会话中已经提交的数据,解决了脏读。但可能发生
不可重复读现象,也就是可能在一个事务中两次查询结果不一致。

C. 可重复度

Repeatable Read 可重复读:解决了不可重复读,它确保同一事务的多个实例在并发读取数据
时,会看到同样的数据行。不过理论上会出现幻读,简单的说幻读指的的当用户读取某一范围的数
据行时,另一个事务又在该范围插入了新行,当用户在读取该范围的数据时会发现有新的幻影行。

D. 可串行化

Serializable 串行化:所有的增删改查串行执行。它通过强制事务排序,解决相互冲突,从而解决
幻度的问题。这个级别可能导致大量的超时现象的和锁竞争,效率低下。
事务隔离级别与锁的关系
1. 其实是对MVCC 和 锁 的封装, 隐藏了细节
2.  锁是数据库实现并发控制的基础,事务隔离性是采用锁来实现,对相应操作加不同的锁,就可以防 止其他事务同时对数据进行读写操作。
3.  对用户来讲,首先选择使用隔离级别,当选用的隔离级别不能解决并发问题或需求时,才有必要在 开发中手动的设置锁。
MySQL默认隔离级别:可重复读

3.2 MySQL隔离级别控制

查看事务隔离级别
  1. showvariableslike'tx_isolation';
  2. select@@tx_isolation;

设置隔离级别:

  1. settx_isolation='READ-UNCOMMITTED';
  2. settx_isolation='READ-COMMITTED';
  3. settx_isolation='REPEATABLE-READ';
  4. settx_isolation='SERIALIZABLE';

四. 锁机制

4.1 锁的分类

从操作的粒度可分为表级锁、行级锁和页级锁。
从操作的类型可分为读锁和写锁。
从操作的性能可分为乐观锁和悲观锁

4.2 行锁原理

在InnoDB中, 我们可以使用行锁和表锁, 其中锁又分为排他锁和共享锁
注意:InnoDB是通过对索引数据页上的记录进行加锁
主要算法有: 记录锁, 间隙锁, 组合锁
RecordLock 锁:锁定单个行记录的锁。(记录锁, RCRR 隔离级别都支持
GapLock 锁:间隙锁,锁定索引记录间隙,确保索引记录的间隙不变。(范围锁, RR 隔离级别支
持)
Next-key Lock 锁:记录锁和间隙锁组合,同时锁住数据,并且锁住数据前后范围。(记录锁 +
围锁, RR 隔离级别支持)

总结: 在RR隔离级别下, InnoDB采用的是组合锁, 如果有唯一索引则, 降为记录锁, 锁住当前行, 如果没有唯一索引,则不会降锁, 除了本行, 旁边俩行也会被锁住。 无索引, 直接退化到表锁

4.3 悲观锁

行锁、表锁、读锁、写锁、共享锁、排他锁等,这些都属于悲观锁范畴。
共享锁(行级锁 - 读锁)
指每个事务都可以对同一行开启共享锁, 不冲突, 都能访问到数据, 但是不能修改数据
select ... lock in share mode
总结:事务使用了共享锁(读锁),只能读取,不能修改,修改操作被阻塞。
排他锁(行级锁 - 写锁)
总结:事务使用了排他锁(写锁),当前事务可以读取和修改,其他事务不能修改,也不能获取记录锁(select... for update )。如果查询没有使用到索引,将会锁住整个表记录。

4.4 乐观锁

乐观锁是一种采用无锁的方式, 需要开发者自己去实现,我们可以通过 设置版本号 和 时间戳 来进行控制数据的一致性。 类似于 CAS操作, 期待值和当前值, 保持一致才能修改成功。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/387228
推荐阅读
相关标签
  

闽ICP备14008679号