事务&锁机制&MVCC

事务&锁机制&MVCC

事务的特性
1.原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。原子性由undo log日志来保证,因为undo log记录着数据修改前的信息,如要insert一条数据,undo log会记录着一条delete日志,要update一条数据时,undo log会记录一条旧值的update记录。如果执行事务中出现异常情况,执行回滚,Innodb引擎就是利用undo log记录下来日志,来将数据恢复到事务开始之前。
2.一致性:执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账人和收款人的总和是一致的。
3.隔离性:并发访问数据库时,一个用户的事务不被其他事务干扰,各并发事务之间数据库是独立的。
4.持久性:一个事务被提交后,它对数据库中的数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
并发事务带来的问题
1.脏读:当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据就是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
2.丢失修改:指一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。例如:事务1读取某表中的数据A=20,事务2也读取数据A=20,事务1修改数据A=A-1,事务2修改数据A=A-1,最终结束后A=19,事务1的修改被丢失。
3.不可重复读:指在一个事务内多次读取同一个数据,在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,导致第一个事务两次读同一数据结果可能不太一样,这就发生了一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
4.幻读:幻读与不可重复读类似,它发生在一个事务读取了几行数据后,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的数据,就像产生了幻觉一样,因此称为幻读。
事务的隔离级别
1.读未提交(READ-UNCOMMITTED):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读,幻读,不可重复读。
2.读已提交(READ-COMMITTED):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读和不可重复读仍有可能发生。
3.可重复读(REPEATABLE-READ):同一个事务对同一条数据多次读取的结果是一致的,除非数据是被本身事务自己所修改的,可以阻止脏读和不可重复读,但幻读仍有可能发生。
4.可串行化(SERIALIZABLE):最高的隔离级别,完全服从ACID的隔离级别,所有事务依次逐个执行,这样事务之间完全不可能产生干扰,可以避免脏读,不可重复读,幻读。但开发中不会使用,效率太低。

MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。我们可以通过SELECT @@tx_isolation;命令来查看,MySQL 8.0 该命令改为SELECT @@transaction_isolation;

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 READ-COMMITTED(读取提交内容) ,但是你要知道的是 InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读) 并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下一般会用到 SERIALIZABLE(可串行化) 隔离级别。

mysql锁详解
根据加锁的范围,mysql里面的锁大致可以分成全局锁、表级锁和行级锁。
全局锁
全局锁就是对整个数据的实例加锁,一般用于需要整个库只读的场景。
表级锁
mysql表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)
表锁的语法是lock tables … read/write,可以使用unlock tables主动释放锁,也可以在客户端断开的时候自动释放,lock tables处了会限制别的线程对表的读写意外,也限定了本线程接下来的操作对象。

另一个表级锁是MDL,MDL不需要显示的使用,在访问一个表的时候会被自动加上,MDL的作用是保证读写的正确性。
在msql5.5以后引入了MDL,当对一个表做增删改查的操作时,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。

1.读锁之间不互斥,因此可以有多个线程同时对一张表进行增删改查
2.读写锁之间、写锁之间是互斥的,用来保证变更表结构的安全性。因此,如果有两个线程同时给一个表加字段,其中一个要等另外一个执行完才能开始执行
sessionA启动执行查询,这时候会对表加一个MDL读锁,sessionB启动执行查询,这时候会对表加MDL读锁,因此是可以正常执行的。sessionC执行修改表字段操作,sessionC会被blocked,是因为sessionA的读锁还没有释放,而sessionC需要MDL写锁,所以只能被阻塞,后面对此表执行的获取的MDL读锁和写锁都会被sessionC阻塞,也就是说此时当前表不可以执行读写。

行锁
mysql的行锁是引擎层由各引擎自己实现的,但不是所有引擎都支持行锁,比如MYISAM引擎就不支持行锁。
行锁是针对数据表中记录的锁,比如事务A更新了一行,事务B也要更新同一行,就必须等到事务A更新完成之后才能更新。
在InnoDB引擎中行锁是需要的时候才加上的,但并不是不需要了就立刻释放的,而是要等到事务结束的时候才会释放。这就是两阶段锁协议。如果事务执行中需要锁多行,要把最可能造成锁冲突、最可能影响并发度的锁往后放。

msyql解决死锁方式
一种情况是直接进入等待,然后超时,这个超时时间可以通过参数innodb_lock_wait_timeout来设置,在InnoDB引擎中默认值为50m。
另一种策略是发起死锁检测,发现死锁后,主动回滚死锁联调中的某一事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑。

InnoDB对MVCC的实现
Mvcc的实现依赖与隐藏字段、read view、undo log。在内部实现中InnoDB通过数据行的DB_TRX_ID和read view来判断数据的可见性,如果不可见则通过数据行的DB_ROLL_PTR找到undo log中的历史版本。每个事务读到的数据版本可能是不一样的,在同一个事务中,用户只能看见该事务创建read view之前提交的修改和该事务本身的修改。

在内部,InnoDB 存储引擎为每行数据添加了三个
隐藏字段:

DB_TRX_ID(6字节):表示最后一次插入或更新该行的事务 id。此外,delete 操作在内部被视为更新,只不过会在记录头 Record header 中的 deleted_flag 字段将其标记为已删除
DB_ROLL_PTR(7字节) 回滚指针,指向该行的 undo log 。如果该行未被更新,则为空
DB_ROW_ID(6字节):如果没有设置主键且该表没有唯一非空索引时,InnoDB 会使用该 id 来生成聚簇索引

Read View 主要是用来做可见性判断,里面保存了 “当前对本事务不可见的其他活跃事务”

主要有以下字段:

m_low_limit_id:目前出现过的最大的事务 ID+1,即下一个将被分配的事务 ID。大于等于这个 ID 的数据版本均不可见
m_up_limit_id:活跃事务列表 m_ids 中最小的事务 ID,如果 m_ids 为空,则 m_up_limit_id 为 m_low_limit_id。小于这个 ID 的数据版本均可见
m_ids:Read View 创建时其他未提交的活跃事务 ID 列表。创建 Read View时,将当前未提交事务 ID 记录下来,后续即使它们修改了记录行的值,对于当前事务也是不可见的。m_ids 不包括当前事务自己和已提交的事务(正在内存中)
m_creator_trx_id:创建该 Read View 的事务 ID

undo-log
undo log 主要有两个作用:

当事务回滚时用于将数据恢复到修改前的样子
另一个作用是 MVCC ,当读取记录时,若该记录被其他事务占用或当前版本对该事务不可见,则可以通过 undo log 读取之前的版本数据,以此实现非锁定读
在 InnoDB 存储引擎中 undo log 分为两种: insert undo log 和 update undo log:

insert undo log :指在 insert 操作中产生的 undo log。因为 insert 操作的记录只对事务本身可见,对其他事务不可见,故该 undo log 可以在事务提交后直接删除。不需要进行 purge 操作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值