事务的四个基本特性:ACID,原子性,一致性,隔离性,持久性。
事务的脏读、脏写、不可重复读、幻读等问题,主要发生在并发事务中。没有并发事务,就不会有上述问题。
事务并发时,会带来两个问题:
写冲突:多个事务同时修改同一条数据,写的先后顺序如何确定?一个事务已经提交了,另一个事物回滚了,怎么办?
读写冲突:一个事务在写数据,另一个事务要读数据,未提交事务的数据要不要展示给读数据的事务看?
这种读写冲突导致的问题,前辈们已经总结好了,分别是:脏写、脏读、不可重复读、幻读
事务的四个原则中,隔离性,说明事物之间应该是互不干扰的,同时执行的事务不能相互冒犯。如果事务不加以认为控制,就是这样混乱的,因此才有了一致性这个概念,用来将事务之间的影响降到最低。
原始的事务,是混沌状态的,无序的。只有用四个基本原则给限制起来,才能为我们所用。
脏写
table 中name字段原值为C
事务A和B按照如下时间线运行。事务A先提交事务,此时数据修改为A,之后事务B回滚,table中name字段值回滚为C。
此时,对事务A来说,就发生了脏写。
脏读
table 中name字段原值为C
事务A第一次查询,值为C,此时事务B更新为B,事务A第二次查询,值为B,事务B回滚,事务A第三次查询,值为C。对于事务A来说,就发生了脏读。按照事务之间不会相互冒犯来说,事务A从头到尾读到的值都应该是C,不会出现一会是C 一会是B的情况。
脏读和脏写共同之处:
● 发生的原因都是另一个事物通过undo log进行回滚所导致的
● 对相同的数据做了操作
● 脏读和脏写所操作的数据也叫做脏数据(在内存中修改了还未及时刷入磁盘的数据)
为了防止脏读,每次写入前,数据库都会记住旧值。 当前事务尚未提交时,其他事务的读取都会拿到旧值。当前事务提交后,其他事务才能读取到新值。
为了防止脏写,数据库一般用行锁。当事务想要修改特定的行时,必须先获得该行的锁。一次只有一个事务可持有任何给定行的锁。如果另一个事务要写入同一行,就必须等到第一个事务提交或回滚后。
不可重复读
table 中name字段原值为C
它是指在同一个事务里面,查询同一条数据,每次查询到的数据都不一样。是不是和脏读很像?区别在于脏读是由事务回滚导致每次读取的数据不一样,不可重复读是因为事务提交导致每次读取数据不一致。
幻读
table 中name字段原值为C。
事务第一次查询到一条数据,第二次查询到两条数据。
是不是和不可重复读很像?区别在于不可重复读 读取的是同一条数据,另一个事务更新,导致读到的同一条数据的某个字段值不一致。幻读则是另一个事务插入,导致读到的数据总条数不一致。
隔离级别
事务的初始状态是混沌的,无序的,因此需要给事务一个规则,让他们为我所用。
隔离级别,就是控制事务之间关联关系的。
read uncommited-读未提交:可以读取到未提交事务的数据。相当于没有隔离级别。事务处于混沌状态
read commited-读已提交:可以读取到其他事务已经提交的数据。mysql默认隔离级别。
repeatable read 可重复读:事务开启之后,在任何时间节点,不论其他事务是否提交,该事务读取到的值都是一样的。相当于有了一个数据库的副本。
serializable-串行:每次只能执行一个事务,所有事务排着队进行处理。完全禁止并发。实际中不会使用这个级别,性能损耗太大了。