事务: 简单的说,就是一组数据库操作,要么全部成功,要么全部失败。mysql中不是所有的存储引擎都可以使用事务,就像innodb支持事务,而在5.5版本以前默认的存储引擎MyISAM就不支持事务,这可能也是后来MyISAM被innodb所取代的原因之一。
举一个烂大街的例子来说明为什么要使用事务?:userA给userB转账一个亿 100块,如果a给b转账的过程中突然发生某些事故,导致此时a的100元已经扣除,b却没有收到,这怎么办?为了防止这种事情的发生,就有了事务。
一、简介
1、事务的4种特性(ACID)
(1)原子性
一个事务是一个不可分割的工作单位,要么都做,要么都不做。
(2)一致性
事务必须使数据库从一个一致性状态变换到另一个一致性的状态,也就是说一个事务执行前和执行后必须保持一致性的状态。
也就是说用户a和用户b两个人账户总额为500,无论两个人之间如何互相转账,两个人账户加起来都是500。
(3)持久性
事务一旦提交,对数据库中数据的改变是永久性的,即使数据库系统发生故障,也不会丢失提交事务的操作。
(4)隔离性
一个事务的执行不能被其他事务所干扰。比如多个用户并发访问数据库中同一张表,数据库对每个用户开启一个事务,事务a要么在事务b开始之前结束,要么在事务b结束之后开始。多个并发事务之间要相互隔离。
2、多种事务可能会引发的问题
(1)脏读
一个事务读到了其他事务未提交的数据。
(2)幻读
事务a中根据一个查询条件,查询到结果条数为n,此时另一个事务插入一条符合此查询条件的数据,事务a再次查询,查到结果条数为n+1,这种情况叫幻读
(3)不可重复读
事务a根据一个查询条件,查询结果为x,此时另一个事务把这条数据修改为y,事务a再次查询,查询到的结果为y,这种情况叫不可重复读
二、事务的隔离性
事务的隔离性越高,执行效率就会越低,当用户量很大,需要很大的吞吐量时,可以选用隔离级别比较低的事务,不过要牺牲数据的正确性。所以需要慎重选择。
mysql默认的隔离级别是可重复读;oracle只支持串行化和读提交,默认为读提交。
1、事务的4种隔离级别
(1)读未提交
事务还没有提交时,它的变更就能被其他事务所看到。
隔离级别最低,任何情况都无法保证
(2)读提交
事务已经提交才会被其他事务所看到。
可以避免脏读的情况发生
(3)可重复读
事务执行过程中看到数据总是和事务开始时所看到的数据是一致的。相当于一个静态视图,不会被其他事务更新所影响。未提交的事务也不会被其他事务所看到。
可以避免脏读和不可重复读的现象发生
(4)串行化
事务开启后,读要加读锁,写要加写锁,出现读写冲突时,一个事务要等到另外一个事务执行结束后才会执行操作。
可以避免脏读、幻读、不可重复读的发生,隔离级别最高,但是效率比较低。
2、思考🤔
假设数据表T中只有一列,其中一行的值为1,下面是按照时间顺序执行两个事务的行为,在不同的隔离级别下,事务A的结果分别是多少(V1 V2 V3的值分别是多少)
mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(1);
读未提交:v1=2 v2=2 v3=2
读提交: v1=1 v2=2 v3=2
不可重复读:v1=1 v2=1 v3=2
串行化: v1=1 v2=1 v3=2