什么是事务
数据库事务,事务就是【一组原子性的SQL】,独立不可分割的工作单元,要保证这个事务里的SQL 要么全部成功要么全部失败。
四大特性
ACID
Atomicity 原子性(回滚日志 undolog)
Durability 持久性 (重做日志 redolog)
isolation 隔离性
consistency 一致性
事务并发存在的问题
脏读
幻读
不可重复读
不可重复读与幻读有什么区别?
不可重复读:重点是在于修改,在一个事务中,同样的条件,第一 次读取的数据与第二次【数据不一样】(因为中间有其他事务对这 个数据进行了修改)
幻读:重点在于新增,在一个事务中,同样的条件(范围),第一 次读取和第二读取【记录条数不一样】(因为中间有其他事务在这个范围里插入、删除了的数据)
数据库隔离性
Read UnCommited 读取未提交
没有解决任何问题,存在脏读,因为他就是读取最新的数据。
Read Commited 读取已提交
只读取已提交的的事务,可以解决脏读问题。
Repeatable Read
RR级别解决了脏读、不可重复读、幻读的问题。在第一次读取时,他会生成一次ReadView,之后每次读取都只会读取这个 ReadView.
Serializable 串行执行
串行排队读取,性能最低。
MVCC 非锁定一致性读取
非锁定一致性查询将看到由以下事务所做的更改在该时间点 前提交,并且未进行任何更改稍后或未提交的事务。
官网地址:https://dev.mysql.com/doc/refman/8.0/en/innodb-con sistent-read.html
如何实现?
每个事务都有一个事务ID,并且是递增,我们后续MVCC的原理都是基于它去完成。
效果:建立一个快照,同一个事务无论查询多少次都是相同的数据。
一个事务能看见的版本:
1. 第一次查询之前已经提交的版本
2. 本事务的修改
一个事务不能看见的版本:
1. 在本事务第一次查询之后创建的事务(事务ID比我大)
2. 活跃中的(未提交)的时候的修改。
然后InnoDB会在每行的后面都添加 3个隐藏字段。
DB_TRX_ID:表示最近一次对本记录做修改/插入的事务ID。
DB_ROLL_PTR:回滚指针,指向当前记录行的undo log信息
DB_ROW_ID:随着新行插入而单调递增的行ID。
ReadView(读视图) 结构
什么是ReadView,事务进行快照读、当前读操作的 时候,产生一个读视图,在事务执行读的一刻,生成数据库系统当前的一个快照,记录并且维护系统当前活跃事务ID。 (当每个事务开启时,都会被分配一个ID, 这个ID是递增的,所以最新的事务,ID值越大)
这里解释一下,什么是快照读: 普通读的执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁
当前读对读取的记录加锁, 阻塞其他事务同时改动相同记录,避免出现安全问题。
快照读:MVCC Read View。
当前读:对记录加锁,阻塞其他事务同时修改相同的记录,避免安全的问题。
Read View 判断规则
数据行的隐藏列 trx_id = creator_trx_id,在本事务修改的我是可见的。
trx_id = min_trx_id(未提交的事务最小ID),说明这个版本在ReadView 视图创建之前已经创建,但是还未提交,所以不能够读取。
trx_id在我们的活跃的m_ids数组里, trx_id < min_trx_id, 说明这个版本在ReadView 开启之前事务已经提交了,可以访问。
trx_id >= max_trx_id,说明这个版本在我ReadView 开启之后才创建的,不管你是否提交我都无法访问。
MVCC 总结:
MVCC 是适合用于处查询的时候使用,能提供很高的性能,我们的事务不仅仅是只有读,我们还有写情况,为了保证数据不丢失,我们需要拿到最新的数据进行更改。
数据库并发场景有三种,分别为:
1、读读: 不存在任何问题,也不需要并发控制
2、读写、写读: 有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读、幻读、不可重复读。
3、写写: 有线程安全问题,可能存在更新丢失问题。
MVCC是一种用来解决读写冲突的无锁并发控制,也就是为事务分配单项增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联.读操作只读该事务开始前的数据库的快照,所以MVCC可 以为数据库解决一下问题:
1、在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写 操作也不用阻塞读操作,提高了数据库并发读写的性能
2、解决脏读、幻读、不可重复读等事务隔离问题,但是不能解决更新丢失问题。
LBCC 锁定读取
如果查询数据,然后在其他的事务可能会对你查询的数据进行更改,(SELECT) 常规语句没有给出足够的保护,其他事务可以更新或删除刚刚查询的相同行。
粒度:表锁、行锁
类型:共享(读)、排它(写)、意向共享、意向排他
用户:乐观锁、悲观锁
算法:记录、临检、间隙锁
锁类型
共享锁
我们发现加上了共享锁之后,其他事务是可以加共享锁,意味 着共享锁之间不互斥,但是其他事务不可以对加了共享锁的数据进 行加排他锁,意味着共享锁与排他锁互斥。
排他锁
我们发现一个数据加上了排他锁之后,其他数据对其进行加排他锁是不可行的,意味着排他锁与排他锁互斥。如果我们再对这个 数据加上共享锁也是不行的,因为排他锁与其他锁(排它锁、共享 锁)都互斥。
锁算法
记录锁
阻止任何其他事务插入、更新或删除值为 的行。
SELECT id FROM t WHERE id = 10 FOR UPDATE; 用主键加锁
间隙锁
间隙锁是索引记录之间间隙上的锁,或锁在第一个索引记录之前或之后的间隙上。例如,阻止插入其他事务的insert into;间 隙锁是索引记录之间间隙上的锁,或锁在第一个索引记录之前或之 后的间隙上。例如,阻止插入其他事务的 into 列的值。
临检锁
记录锁+临检锁的组合 InnoDB执行行级锁定的方式是,当它搜索或扫描表索引时,它会对遇到的索引记录设置共享或独占锁。因此,行级锁实际上是索引记录锁。索引记录上的临检锁锁定也会影响该索引记录之前的“间 隙”。也就是说,临检锁是索引记录锁加上索引记录之前间隙上的间隙锁。