事务的特性
- 原子性:原子性是指单个事务本身涉及到的数据库操作,要么全部成功,要么全部失败。
- 隔离性:隔离性侧重于多个事务之间的特性,也就是说多个事务之间是没有相互影响的,比如A给B转账;和B给C转账这两个事务是没有影响的
- 一致性:一致性指事务执行前后的状态要一直,简单的例子还是转账,原来AB账户的钱加一起是100,相互转账完成时候彼此还是100(抛出别人给其转账的事务发生),所以一致性,理解起来就是事务执行前后的数据状态是稳定的,对于转账就是金额稳定不变,对于其他的事务操作就是事务执行完成之后,数据库的状态是正确的,没有脏数据。
持久性:持久性是数据库一旦完成事务的提交之后,那么这个事务的状态就会持久在数据库中,而不用担心数据库 自身是否存在问题,只要事务完成提交,那么这个事务的操作都会影响数据库最终的状态。
事务的锁
根据读写,分为共享锁S和排它锁X
共享锁:即读加锁,不能写并且可并行读
排它锁:写加锁,其他读写都阻塞根据加锁范围分为表锁、行锁、间隙锁
表锁:锁整个表,性能开销最大,其他的读写都要挂起
行锁:锁整个行,以默认隔离级别为例:如果是读,那么会上共享锁,不允许写,如果是写,那么改行其他事务无论读写都得阻塞
间隙锁:间隙锁分为两种,一种是不包含记录间隙锁(GAP),一种是包含记录间隙锁(Next-Key Lock: Gap Lock+Record Lock)间隙锁详细解释RAED UNCOMMITED:读未提交,任何操作都不加锁,所以能读到其他事务修改但未提交的数据行,也称之为脏读(Dirty Read);不使用一致性读视图。
- READ COMMITED:读操作不加锁,写操作加锁。读被加锁的数据时,读事务每次都读undo log中的最近版本,因此可能对同一数据读到不同的版本(不可重复读),但能保证每次都读到最新的数据(事务提交之后的,不可重复读,两次读不一致),但是不会在记录之间加间隙锁,所以允许新的记录插入到被锁定记录的附近,所以再多次使用查询语句时,可能得到不同的结果(Non-Repeatable Read);每条SQL执行前会重新计算一个一致性读视图
- REPEATABLE READ:第一次读数据的时候就将数据加行锁(共享锁),使其他事务不能修改当前数据,即可实现可重复读。但是不能锁住insert进来的新的数据,当前事务读取或者修改的同时,另一个事务还是可以insert提交,造成幻读;在执行第一条SQL创建一致性读视图
(mysql的可重复读的隔离级别解决了 “不可重复读” 和 “幻读” 2个问题,因为使用了间隙锁) SERIALIZABLE:InnoDB 锁表,读锁和写锁阻塞,强制事务串行执行,解决了幻读的问题;
MVCC
搞清楚了各个隔离级别 下的锁的使用情况,那么在默认的隔离级别下,innoDB如何实现事务的隔离性并保证其高效的并发性呢,那么就应该谈一谈MVCC多版本控制,基于此有必要了解一下多版本控制的概念。
一致性读视图ReadView:ReadView所解决的问题是使用READ COMMITTED和REPEATABLE READ隔离级别的事务中,不能读到未提交的记录,这需要判断一下版本链中的哪个版本是当前事务可见的。
ReadView中主要包含4个比较重要的内容:ReadView详细解释
- m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
- min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
- max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
- creator_trx_id:表示生成该ReadView的事务的事务id。
- MVCC:多版本并发控制(MVCC,Multiversion Currency Control)。一般情况下,事务性储存引擎不是只使用表锁,行加锁的处理数据,而是结合了MVCC机制,以处理更多的并发问题。Mvcc处理高并发能力最强,这种方式系统开销 比最大(较表锁、行级锁),这是最求高并发付出的代价。
- innodb存储的最基本row中包含一些额外的存储信息 DATA_TRX_ID,DATA_ROLL_PTR,DB_ROW_ID,DELETE BIT
- 6字节的DATA_TRX_ID 标记了最新更新这条行记录的transaction id,每处理一个事务,其值自动+1
- 7字节的DATA_ROLL_PTR 指向当前记录项的rollback segment的undo log记录,找之前版本的数据就是通过这个指针
- 6字节的DB_ROW_ID,当由innodb自动产生聚集索引时,聚集索引包括这个DB_ROW_ID的值,否则聚集索引中不包括这个值.,这个用于索引当中
- DELETE BIT位用于标识该记录是否被删除,这里的不是真正的删除数据,而是标志出来的删除。真正意义的删除是在commit的时候