Mysql原理浅析——事务理论

Mysql中的事务

事务的四大特征

  • 原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。
  • 一致性: 事务执行前后,数据保持一致,多个事务对同一个数据读取的结果是相同的。
  • 隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。
  • 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

事务的并发问题

  • 脏读:一个事务正在对一条记录进行修改,这个事务完成并提交前,这条记录的数据就处于不一致的状态。此时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据。
  • 不可重复读:一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”,重复读到的是不同的数据。
  • 幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

事务的隔离级别

  • 读未提交(READ UNCOMMITED):事务中的修改,即使没有提交,对其它事务也是可见的 。事务可以读取到未提交的数据,也叫脏读。这个级别会导致很多问题,性能也不会提高很多,所以实际很少使用。
  • 读提交(READ COMMITED):大多数数据库的默认隔离级别都是读提交(mysql不是),读提交满足一个事务从开始到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有不可重复读的问题,即两次执行相同的查询结果可能不一样。
  • 可重复读(REPEATABLE READ):读提交解决了脏读的问题,该级别保证了在同一个事务中多次读取同样记录的结果是一致的(解决方法是:在事务期间其它线程来查询,读提交会直接返回事务开始时的状态,而可重复读会阻塞等待事务结束后返回),但是还是不能解决幻读的问题。可重复读是Mysql的默认隔离级别。
  • 可串行化(SERIALIZABLE):是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。即串行化会在每一行数据上都加锁,所以可能导致大量的超时和锁争用问题。

InnoDB中的锁

InnoDB使用MVCC来支持高并发,并且实现了四个标准的隔离级别。其默认级别是REPEATABLE READ,并且通过间隙锁策略防止幻读。间隙锁使得InnoDB不仅仅锁定查询的行,还会对索引中的间隙进行锁定以防止幻影行的插入。

多版本并发控制——MVCC原理

(1)MVCC是行级锁的一个变种,但是他在很多情况下避免了加锁操作,因此开销更低。
(2)InnoDB的MVCC,是通过在每行记录后保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存了行的过期时间,当然存储的并不是实际的时间值,而是系统的版本号。每开始一个新的事务,系统版本号都会自动递增。
(3)以下是在REPEATABLE READ隔离级别下,MVCC具体的操作:

  • SELECT:InnoDB会根据以下两个条件检查每行记录:InnoDB只查找版本小于当前事务的数据行(也就是行的系统版本号小于或等于事务的系统版本号),这也做可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的;行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,在事务开始之前未被删除。
  • INSERT:InnoDB为新插入的每一行保存当前系统版本号作为行版本号。
  • DELETE:InnoDB为删除的每一行保存当前系统版本号作为行删除表识。
  • UPDATE:InnoDB插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除表示。

实现事务的日志文件

undo log保证了事务的原子性

  • undo log是重做日志,提供前滚操作。
  • undo log是逻辑日志,记录的是这个语句的逻辑上的状态。
  • undo log记录修改前记录,用于回滚和多版本并发控制.
  • 回滚: 未提交的事务,即该事务未被执行commit命令。但是此时,该事务修改的脏块中也有可能一部分脏块写入到数据文件中了。如果此时数据库实例崩溃了,则当数据库实例恢复时,就需要用回滚(这个机制)来将先前那部分已经写入到数据文件的脏块从数据文件上撤销掉。

redo log保证了事务的持久性

  • Redo log可以简单分为以下两个部分:1是保存在内存中的重做日志的缓冲,是易失的;2是保存在硬盘中重做日志文件,是持久的。
  • InnoDB的更新操作采用的是 Write Ahead Log (预先日志持久化)策略,即先写日志,再写入磁盘。
  • 当事务commit提交时,innodb引擎先将 redo log buffer 写入到 redo log file 进行持久化,待事务的commit操作完成时才算完成。这种做法也被称为 Write-Ahead Log(预先日志持久化),在持久化一个数据页之前,先将内存中相应的日志页持久化。
  • InnoDB使用fsync操作:在每次将redo buffer写入os cache文件系统缓存后,InnoDB存储引擎都需要调用一次 fsync操作,保证立即由os cache文件系统缓存写入redo log file,防止断电后缓存中数据的丢失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值