一、什么是事务
事务就是一组独立不可分割的工作单元,事务中的操作要么全部执行,要么都不执行,对应的是现实中一种比较特殊的业务需求,比如银行转账,扣减金额和增加金额两个操作要么全部成功,要么全部失败,不能存在中间状态
二、事务的四大特性(ACID)
原子性(Atomicity):事务是一个整体,要么全部成功要么全部失败 一致性(Consistency):事务开始之前和结束以后,数据需要符合现实世界中的约束 隔离性(Isolation):不同的事务之间不能互相影响,就像两次转账应该是互不影响的 持久性(Durability):已经提交的事务对数据的修改,应该是永久保存在下来
三、InnoDB事务特性的实现原理
3.1 原子性
原子性在数据库中的体现就是事务回滚,回滚能够撤销所有已经执行的sql语句,InnoDB实现回滚靠的是回滚日志(undo log)
InnoDB存储引擎提供两种事务日志:redo log(重做日志)和undo log(回滚日志),其中redo log用于保证事务持久性;undo log则是事务原子性和隔离性实现的基础
当事务对数据库进行修改时,InnoDB会生成相应的undo log,它记录的是sql执行相关的信息,如果事务执行失败或调用了rollback,发生回滚,InnoDB会根据undo log的内容做与之前相反的工作,对于insert执行delete,对于delete执行insert,对于update执行相反的update把数据改回去,将数据回滚到修改之前的样子
以update操作为例:当事务执行update时,其生成的undo log中会包含被修改行的主键(以便知道修改了哪些行)、修改了哪些列、这些列在修改前后的值等信息,回滚时便可以使用这些信息将数据还原到update之前的状态
3.2 持久性
持久性的对应数据库中就是说对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。
事务提交时同步的将数据写到硬盘就可以保证持久性
但是InnoDB作为MySQL的存储引擎,还需要考虑到性能,mysql数据是存放在磁盘中的,但如果每次读写数据都需要磁盘IO,效率会很低。为此,InnoDB提供了缓存(Buffer Pool)
Buffer Pool中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中
缓存的使用大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时缓存中修改的数据还没有刷新到磁盘,就会导致数据的丢失,这样事务的持久性就无法保证
在事务提交时同步的把该事务所修改的所有页面都刷新到磁盘也能保证持久性
同样的Innodb为了性能没有选择这么做,因为
必须按照数据页进行刷新:有时候我们仅仅修改了某个页面中的一个字段,事务提交时不得不将一个完整的页面从内存中刷新到磁盘
可能要进行多次的磁盘IO:如果一个事务修改了非常多的记录,但这些记录可能在不同的页面而且这些页面可能并不相临,这就会导致将这些页面刷新到磁盘时要进行多次的磁盘io操作
Innodb使用重做日志(redo log)来解决了这个问题,实现持久性的同时保证了性能。