原子性(Atomicity) :语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;实现主要基于undo log日志实现的。
持久性(Durability :保证事务提交后不会因为宕机等原因导致数据丢失;实现主要基于redo log日志。
隔离性(Isolation) :保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR,RR的实现主要基于锁机制、数据的隐藏列、undo log和类next-key lock机制。
一致性(Consistency) :事务追求的最终目标,一致性的实现既需要数据库层面的保障,也需要应用层面的保障。
原子性事务的原子性就如原子操作一般,表示事务不可再分,其中的操作要么都做,要么都不做;如果事务中一个SQL语句执行失败,则已执行的语句也必须回滚,数据库退回到事务前的状态。只有0和1,没有其它值。
事务的原子性表明事务就是一个整体,当事务无法成功执行的时候,需要将事务中已经执行过的语句全部回滚,使得数据库回归到最初未开始事务的状态。
事务的原子性就是通过undo log日志进行实现的。当事务需要进行回滚时,InnoDB引擎就会调用undo log日志进行SQL语句的撤销,实现数据的回滚。
持久性事务的持久性是指当事务提交之后,数据库的改变就应该是永久性的,而不是暂时的。这也就是说,当事务提交之后,任何其它操作甚至是系统的宕机故障都不会对原来事务的执行结果产生影响。
事务的持久性是通过InnoDB存储引擎中的redo log日志来实现的,具体实现思路见下文。
隔离性原子性和持久性是单个事务本身层面的性质,而隔离性是指事务之间应该保持的关系。隔离性要求不同事务之间的影响是互不干扰的,一个事务的操作与其它事务是相互隔离的。
由于事务可能并不只包含一条SQL语句,所以在事务的执行期间很有可能会有其它事务开始执行。因此多事务的并发性就要求事务之间的操作是相互隔离的。这一点跟多线程之间数据同步的概念有些类似。
锁机制
事务之间的隔离,是通过锁机制实现的。当一个事务需要对数据库中的某行数据进行修改时,需要先给数据加锁;加了锁的数据,其它事务是不运行操作的,只能等待当前事务提交或回滚将锁释放。
锁机制并不是一个陌生的概念,在许多场景中都会利用到不同实现的锁对数据进行保护和同步。而在MySQL中,根据不同的划分标准,还可将锁分为不同的种类。
按照粒度划分:行锁、表锁、页锁
按照使用方式划分:共享锁、排它锁
按照思想划分:悲观锁、乐观锁
锁机制的知识点很多,由于篇幅不好全部展开讲。这里对按照粒度划分的锁进行简单介绍。
粒度:指数据仓库的数据单位中保存数据的细化或综合程度的级别。细化程度越高,粒度级就越小;相反,细化程度越低,粒度级就越大。
MySQL按照锁的粒度划分可以分为行锁、表锁和页锁。
行锁:粒度最小的锁,表示只针对当前操作的行进行加锁;
表锁:粒度最大的锁,表示当前的操作对整张表加锁;
页锁:粒度介于行级锁和表级锁中间的一种锁,表示对页进行加锁。
这三种锁是在不同层次上对数据进行锁定,由于粒度的不同,其带来的好处和劣势也不一而同。
表锁在操作数据时会锁定整张表,因而并发性能较差;
行锁则只锁定需要操作的数据,并发性能好。但是由于加锁本身需要消耗资源(获得锁、检查锁、释放锁等都需要消耗资源),因此在锁定数据较多情况下使用表锁可以节省大量资源。
MySQL中不同的存储引擎能够支持的锁也是不一样的。MyIsam只支持表锁,而InnoDB同时支持表锁和行锁,且出于性能考虑,绝大多数情况下使用的都是行锁。
并发读写问题
在并发情况下,MySQL的同时读写可能会导致三类问题,脏读、不可重复度和幻读。
(1)脏读:当前事务中读到其他事务未提交的数据,也就是脏数据。