事务定义
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性。
- 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
- 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。
- 隔离性(Isolation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
- 持久性(Durable):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
事务的隔离级别
- READ UNCOMMITTED(未提交读)
事务中的修改即使没有修改对其他的事务也是可见的,事务可以读取到未提交的数据,这也称为脏读(Dirty Read) - READ COMMITTED
一个事务开始时只能看到已经提交的事务的修改。这个级别也叫不可重复读(nonrepeatable read),因为两次执行同样的查询,可能会得到不一样的结果。 - REPEATABLE READ
该级别解决了脏读的问题,该级别保证了在同一个事务中读取到相同记录的结果是一致的。该级别会产生一个幻读(Phantom Read)的问题,读取某个范围内的记录时,另外一个事务插入了一条新的记录,再次读取时会产生幻行(Phantom Row)。InnoDB已经解决了幻读的问题。这个级别也是MySQL的默认的隔离级别。 - SERIALIZABLE
它通过强制事务串行执行避免了幻读的问题。
MySQL中的锁
表锁
每次开始事务时锁定整张表。
开销小,加锁块;不会出现死锁;锁力度大,出现锁冲突的概率高;并发度最低;一般只适用于数据迁移的场景;
行锁
每次操作锁定一行数据。
开销大,加锁慢;会出现死锁情况;锁粒度小,出现锁冲入的概率小;并发度高;
行锁就是为某行记录加锁,列必须为唯一索引列或主键列,否则加的锁就会变成临键锁,
查询语句必须为精准匹配 = ,不能为 >、<、like等,否则也会退化成临键锁。
间隙锁 (GAP LOCK)
间隙锁基于非唯一索引,它锁定一段范围内的索引记录。比如查询字段区间为1-5,即1-5内的记录行都会被锁住,2、3、4 的数据行的会被阻塞,但是 1 和 5 两条记录行并不会被锁住。
临键锁:
临键锁可以理解为一种特殊的间隙锁,每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该数据行的临键锁时,会锁住一段左开右闭区间的数据。
MVCC多版本并发控制
![](https://i-blog.csdnimg.cn/blog_migrate/05507f5cab921c5872d46555c9487693.png)
更新一条数据时时,会进行如下操作:
- 用排他锁锁定该行
- 记录redo log
- 把该行修改前的值Copy到undo log,即上图中下面的行
- 修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行
如果undo log一直不删除,则会通过当前记录的回滚指针回溯到该行创建时的初始内容,所幸的时在Innodb中存在purge线程,它会查询那些比现在最老的活动事务还早的undo log,并删除它们,从而保证undo log文件不至于无限增长。
Undo 日志版本链是指一条记录在被多个事务修改后,可用于追踪修改就的,可用于回滚的日志记录,每条数据除了可见的数据之外,MySQL还添加了 TRX_ID 和 ROLL_POINTER 两个隐士的字段,通过这两个字段就可以将所有的修改记录串联起来形成了一个历史记录版本链
MySQL在读已提交和可重复读两个级别都实现了mvcc机制。
在可重复读隔离级别,当事务开启,执行任何查询sql时会生成当前事务的一致性视图read-view,该视图在事务结束之前都不会变化(如果是读已提交隔离级别在每次执行查询sql时都会重新生成),这个视图由执行查询时所有未提交事务id数组(数组里最小的id为min_id)和已创建的最大事务id(max_id)组成,事务里的任何sql查询结果需要从对应版本链里的最新数据开始逐条跟read-view做比对从而得到最终的快照结果。
BufferPool缓存机制
![](https://i-blog.csdnimg.cn/blog_migrate/ed5b06416d96a8b3c6fb578397329148.png)
参考文章: https://blog.csdn.net/chen77716/article/details/6742128