MySQL事务

事务是一系列的数据库操作,是数据库应用的基本单位。MySQL 事务主要用于处理操作量大,复杂度高的数据。
MySQL的ACID:
  原子性:事务是一个完整的操作,不可被分割。事务操作要么都成功,要么失败回滚。
  一致性:事务完成时,数据必须处于一致状态
  隔离性:对数据进行修改的所有并发事务是彼此隔离的
  持久性:事务完成时,对数据库的修改被永久保持
实现原理:
  • 原子性:undo log,原子性的关键是事务回滚能够撤销所有成功执行过的sql。当事务对数据库进行修改时,会生成对应的undo log,事务执行失败或调用rollback,事务需要回滚,利用undo log中的信息将数据回滚到修改之前的样子。
  • 一致性:事务执行结束后,数据库的完整性约束没有被破坏,事务执行前后都是合法数据状态。实现的原理:首先是原子性,隔离性,持久性的保证,不然一致性也无法保证。其次是数据库和应用层面的保障。数据库提供了规范,例如字段长度限制,类型限制。应用层面在代码处理这块保证数据的一致性,如转账业务下,接受者跟扣除者账户余额的统一变更。
  • 隔离性:保证事务执行不受其他事务影响。主要实现基于隔离级别,隔离级别的实现原理是锁机制、MVCC
  • 持久性:事务提交后不会因为宕机等原因导致数据丢失,基于redo log+big log。在事务提交后发生宕机等异常,利用redo log和bin log记录操作,用于数据恢复。
并发事务数据问题:
  • 脏读:读到了其他事务还没有提交的数据。
  • 不可重复读:对某数据进行读取过程中,有其他事务对数据进行了修改(UPDATE、DELETE),导致第二次读取的结果不同。
  • 幻读:事务在做范围查询过程中,有另外一个事务对范围内新增了记录(INSERT),导致范围查询的结果条数不一致。
事务隔离级别:
  1、读未提交(RU):一个事务还没提交时,它做的变更就能被别的事务看到。可脏读,不可更新丢失。
  2、读已提交(RC):一个事务提交之后,它做的变更才会被其他事务看到。允许不可重复读,不允许脏读(Oracle数据库默认隔离级别)
  3、可重复读(RR):一个事务执行过程中看到的同一行数据,总是跟这个事务在启动时看到的是一致的。当前事务未提交变更对其他事务也是不可见的,不再允许修改操作。禁止不可重复读和脏读。(MySQL数据库默认隔离级别),幻读会导致多读出数据来,SQL标准的RR不能禁止幻读,但是MySQL的RR可以禁止
  4、序列化(serializable):事务串行化顺序执行,避免脏读、不可重复读、幻读
并发事务可能会造成的问题及解决方案:
并发事务可能造成:脏读、不可重复读和幻读等问题 ,这些问题其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决,解决方案如下:
  • 加锁:在读取数据前,对其加锁,阻止其他事务对数据进行修改。
  • 提供数据多版本并发控制(MultiVersion Concurrency Control,简称 MVCC 或 MCC),也称为多版本数据库:不用加任何锁, 通过一定机制生成一个数据请求时间点的一致性数据快照(Snapshot), 并用这个快照来提供一定级别 (语句级或事务级) 的一致性读取,从用户的角度来看,好象是数据库可以提供同一数据的多个版本。

MVCC

undo log版本链:
  • MySQL中每条数据会有两个隐藏字段,trx_id和roll_pointer。
  • trx_id:6byte, 创建这条记录/最后一次更新这条记录的事务ID roll_pointer:7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)
  • 当对一条记录不停的操作时,undo log会记录这条记录多次修改的回滚日志,roll_pointer会指向每一次修改的上一版本的undo log日志,多个数据快照对应的undo log形成了undo log版本链。
update语句的undo log链形成:
  1. 老记录被复制到rollback segement中形成undo log(回滚日志),trx_id和roll_pointer不动
  2. 新记录的trx_id=当前事务ID,roll_pointer指向老记录形成的undo log
  3. 这样就可以通过roll_pointer找到这条记录的历史版本。如果对同一行记录执行连续的update操作,新记录与undo log会组成一个链表,遍历这个链表可以看到这条记录的变迁
Read View:
  作用是事务执行期间用来定义“我能看到什么数据”。InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前启动了但未提交的所有事务ID。数组里事务ID最小值为低水位,当前系统里已经创建过的事务ID的最大值加1为高水位。这个视图数组和高水位,组成了当前事务的一致性视图。Read View中主要包含4个重要的内容:m_ids、min_trx_id、max_trx_id、creator_trx_id、m_ids(未提交事务集合):表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。 min_trx_id(低水位):表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。 max_trx_id(高水位):表示生成ReadView时系统中应该分配给下一个事务的id值。 creator_trx_id(当前事务):表示生成该ReadView的事务的事务id。

数据版本的可见性规则:基于数据的row_trx_id和一致性视图对比结果得到。
  • 如果被访问版本的row_trx_id属性值与当前事务相同,表明当前事务在访问它自己修改过的记录,该版本可以被当前事务访问。(黄色)
  • 如果被访问版本的row_trx_id属性值小于低水位,表明生成该版本的事务在当前事务生成ReadView前已经提交,该版本可以被当前事务访问。(绿色)
  • 如果被访问版本的row_trx_id属性值大于高水位值,表明生成该版本的事务在当前事务生成ReadView后才开启,该版本不可以被当前事务访问。(红色)
  • 如果被访问版本的row_trx_id属性值高水位与低水位之间,那就判断row_trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。(黄色)
如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录
什么是MVCC?
多版本并发控制, 专门控制多个事务并发运行时,互相之间如何影响。基于undo log多版本链条及Read View机制实现多事务并发执行的RC、RR隔离级别。
MVCC实现RR(可重复读)与RC(读已提交)的底层原理:
  • 读未提交是直接返回记录上的最新值,没有视图概念,而串行化是直接用加锁的方式来避免并行访问。
  • 对于可重复读:Read View在事务启动时创建,整个事务期间所有的SELECT都使用这个视图。
  • 对于读已提交:Read View在SQL语句开始执行时创建,每次读取,都会创建一个新的read view。这样就能读取到其他事务已经COMMIT的内容。
 
posted @ 2025-04-16 17:20  难得  阅读(13)  评论(0)    收藏  举报