ACID
举例说明
假设一个银行的数据库有两张表:支票表(checking)和储蓄表(savings)。现在要从用户jane的支票账户转移200美元到她的储蓄账户,分为3个步骤
- 检查支票账户的余额高于200美元
- 从支票账户余额中减去200美元
- 从储蓄账户余额中增加200美元
上述3个步骤需要在一个事务中,否则要么银行丢钱(第2步失败,第3步成功),要么用户丢钱(第2步成功,第3步失败)
语句
start transaction; select balance from checking where customer_id='10233276'; update checking set balance=balance-200.00 where customer_id='10233276'; update checking set savings=balance+200.00 where customer_id='10233276'; commit;
概念
原子性(Atomicity)
一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。上面的例子2 3 步要么一起成功,要么就得一起失败。
一致性(Consistency)
事务前后数据的完整性必须保持一致。具体点就是,事务中的多条sql语句只有在事务提交之后才会更改数据库,数据库总是从一个一致性的状态转换到另外一个一致性的状态,即使在第3 4条语句执行时系统崩溃,支票账户也不会损失200美元,因为事务没有提交,所以事务最终所做的修改也就不会保存到数据库中
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。当执行完第3条语句,第4条语句还未开始时,此时另一个账户汇款总程序开始运行,在InnoDB默认的事务隔离级别下,支票账户的余额并没有被减去200美元
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响,但实际上不同的持久化策略安全程度不同,有的持久化策略就能够提供非常强的安全保障
事务隔离
可能出现的问题:
建表语句
mysql> CREATE TABLE `t` ( `id` int(11) NOT NULL, `k` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB; insert into t(id, k) values(1,1),(2,2);
1.脏读
前提条件是事务隔离级别为读未提交
d为1时,k最开始等于1,B更新之后,因为事务隔离级别为未提交,事务A此时读到了A第一次更新还未提交的数据,事务A的第一个查询结果为k=2,然后事务B将k又改回了k=1,此时A提交了,A读到的是脏数据,又叫做脏读。
2.不可重复读
前提条件是事务隔离级别为读提交
事务A第一次读id=1这一行,k=1;B将k更新为k=2,提交之后,A再次读id=1时,k=2;
在一个事务中,两次相同查询条件,查询到的结果不一致的情况叫做不可重复读
3.幻读
幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行,幻读仅专指“新插入的行”。
当在可重复读隔离级别下,普通查询都是通过MVCC读的快照,是不会看到别的数据的,幻读只有在当前读才会出现
幻读专指新插入的行,读到原本存在行的更新结果不算,当前读的作用就是能读到所有已经提交记录的最新值
MVCC
可以理解MVCC是一个变种的行锁,是某个时间点的数据快照,也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的,根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据都是一致的
实现
InnoDB的MVCC是通过每行记录后面保存两个隐藏的列实现的,这两个列,一个事保存的行的创建时间,一个保存行的过期时间(或删除时间)每开始一个新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。