事务
ACID原则
原子性:事务必须是一个最小的工作单元,要么成功要么失败
一致性:一个事务必须使数据库从一个一致性状态变换到另一个一致性状态
隔离性:一个事务所做的修改在最终提交之前,是不会被其他事务感知
持久性:一旦事务提交,则其修改会永远保存到数据库中
存储引擎隔离级别
未提交读:事务的修改即使未提交对其他的事务也是可见,会导致脏读
提交读:事务的修改未提交前对其他的事务不可见
可重复读:mysql默认事务隔离级别,保证同一事物多次读取同样的记录结果一致,无法解决幻读问题
可串行化:强制事务串行执行,给每一行数据都加锁
不同的隔离级别会导致不同的问题,例如脏读、不可重复读、幻读。
脏读:A和B两个事务同时修改同一个数据,A修改的提交在B提交之后,导致B好像没有修改,丢失修改
不可重复读:事务A查询数据之后,数据被事务B修改,导致事务A两次读取数据不一致
幻读: 在一次事务里面,多次查询之后,查询的结果集的个数不一致的情况叫做幻读。而多出来或者少的哪一行被叫做幻行
,幻读是由插入或者删除引起的
事务日志
存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久化在硬盘的事务日志中,而不用每次都将修改的数据本身持久化到磁盘。预写式日志。修改数据需要写两次磁盘。
事务日志持久化以后,内存中被修改的数据在后台可以慢慢刷回到磁盘。
多版本并发控制
mysql大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能考虑,实现了多版本并发控制(MVCC)。不同的存储引擎的MVCC实现方式不一样,典型的有乐观并发控制和悲观并发控制。
InnoDB的MVCC是在可重复读的隔离级别下实现的,通过在每行后面记录两个隐藏列来实现,这两个列,一个保存行的创建时间,一个行的过期时间(删除时间)。当然存储的并不是实际的时间,而是系统版本号。每开始一个新的事务,系统版本号会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比价。
select(快照读),因为读的时候快照中的内容,是历史数据,所以读的时候不会有幻读。开启事务后第一个select语句才是快照读的地方,而不是一开启事务就快照读。
a. InnoDB会查找早于当前事务版本的数据行,这样可以确保事务读取的行,要么是在事务开始前存在的,要么是事务自身插入或者修改过的。
b. InnoDB会查找行的删除版本要么未定义,要么大于当前事务版本号的,这可以确保事务读取到的行,在事务开始之前未被删除。
只有符合上述两个条件的记录,才能返回作为查询结果。
insert、delete(当前读,会加锁)
保存存当前系统版本号作为行版本号
update(当前读)
InnoDB为插入一行新记录保存存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
快照读和当前读
快照读:在RC(提交读)隔离级别中每次select都生成一个快照读。在RR(可重复读)隔离级别中,开启事务后第一个select语句才是快照读的地方,而不是一开启事务就快照读,事务后续的读取都是基于最开始创建的快照。
当前读:读取的是最新版本,并且对读取的记录加锁, 阻塞其他事务同时改动相同记录,避免出现安全问题。