事务的性质、并发问题、隔离级别

事务

保证数据库的操作是不可分割的,要么全部执行成功,要么全部执行失败,不允许出现中间状态的数据

操作成功后提交事务

操作失败回滚到没执行到该事务之前

事务特性

原子性

原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在某个中间环节,如果中间某个环节出现了问题,就会回滚到事务执行之前

事务的原子性是通过undo log(回滚日志)来保证的

一致性

一致性:是指事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态,比如A和B分别有800和600,A转账给B200,操作结束后A有600,B有800,加在一起还是1400,而不是A减少200,B由于服务器宕机,未加上200,加起来一共1200

一致性是通过持久性原子性隔离性来保证的

隔离性

隔离性:数据库允许多个并发事务同时对数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。

隔离性是通过MVCC(多版本并发控制)或锁机制来保证的

持久性

事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

原因是,当事务执行后,数据就被写入磁盘,进行了永久性的保存

持久性是通过 redo log(重做日志)来保证的

并行事务引发的问题

并发处理多个事务时候,可能出现脏读不可重复读幻读的问题

脏读

一个事务读到了另一个未提交事务修改过的数据,

举例:

假设有A和B两个事务同时处理,A先开始从数据库取出余额100w之后开始执行,执行结果为200w,但是并未提交,此时事务B开始执行,读取到余额为200w,但是A事务由于发生异常,触发了回滚,导致B的数据过期,因为数据库实际数据是100w,而他操作的数据是200w

不可重复读

在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,这就意味着发生了不可重复读现象

举例:

假设A和B两个事务同时在处理,事务A先开始从数据库读取出余额100w,然后继续执行后续代码逻辑,但是此时事务B对数据进行操作,数据从100w变成200w,之后提交了事务,此时数据库数据为200w,此时事务A再次读取,发现与第一次读取到的数据不同,这种现象称之为不可重复读

幻读

在一个事务内多次查询某个符合查询条件的记录数量,如果出现前后两次查询到的记录数量不一样的情况,意味着发生了幻读的现象

举例:

假如A和B这两个事务同时在处理,事务A先开始从数据库查询账户余额大于100w的记录,发现共有5条,然后事务B也按相同的搜索条件查询出了5条记录,接下来,事务A插入了一条余额超过100w的账号,并且提交了事务,此时事务B再次查询账户余额大于100w的记录,此时查询到的记录数量有6条,发现和之前一次读到的数量不一样,就像幻觉一样,称为幻读

三种问题的严重性

脏读 > 不可重复读 > 幻读

事务的隔离性

SQL标准提供了四种隔离级别来规避这些现象,隔离级别越高,性能效率越低

隔离级别从高到低:串行化,可重复度,读已提交,读未提交

  1. 读未提交:指一个事务还没提交时,他的变更能被其他事务看到

  2. 读提交:指一个事务提交之后,他做的变更才能被其他事务看到

  3. 可重复读:指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB的默认隔离级别

  4. 串行化:会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完毕,才能继续执行

注意:不同隔离级别,并发事务时可能发生的现象也会不同

  1. 读未提交:可能发生脏读,不可重复读,幻读现象

  2. 读提交:可能发生不可重复读和幻读现象

  3. 可重复读:可能发生幻读的现象

  4. 串行化:三种情况都不可能会发生

解决MySQL InnoDB默认级别幻读问题

方法一: 针对快照读(执行select语句),是通过MVCC方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即便途中其他事务插入了一条书库,是查询不出来这条数据的,所以就很好的避免了幻读问题

方法二:

正对当前读(select ... for update等语句),是通过next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行select ... for update等语句的时候,会加上next-key lock,如果有其他事物在next-key lock锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法插入成功,解决了幻读问题

举例说明四种隔离级别

  1. 在「读未提交」隔离级别下,事务B修改余额后,虽然没有提交事务,但是此时的余额已经可以被事务 A看见了,于是事务 A 中余额 V1 査询的值是 200 万,余额 V2、V3 自然也是 200 万了;

  2. 在「读提交」隔离级别下,事务 B修改余额后,因为没有提交事务,所以事务 A 中余额 V1 的值还是100 万,等事务 B提交完后,最新的余额数据才能被事务 A看见,因此额 V2、V3 都是 200 万;

  3. 在「可重复读」隔离级别下,事务 A只能看见启动事务时的数据,所以余额 V1、余额 V2 的值都是100 万,当事务 A 提交事务后,就能看见最新的余额数据了,所以余额 V3 的值是 200 万

  4. 在「串行化」隔离级别下,事务 B在执行将余额 100 万修改为 200 万时,由于此前事务 A执行了读操作,这样就发生了读写冲突,于是就会被锁住,直到事务A提交后,事务 B才可以继续执行,所以从A 的角度看,余额 V1、V2 的值是 100 万,余额 V3 的值是 200万。

四种隔离级别的实现

  1. 对于「读未提交」隔离级别的事务来说,因为可以读到未提交事务修改的数据,所以直接读取最新的数 据就好了;

  2. 对于「串行化」隔离级别的事务来说,通过加读写锁的方式来避免并行访问;

  3. 对于「读提交」和「可重复读」隔离级别的事务来说,它们是通过 Read View 来实现的,它们的区别在于创建 Read View 的时机不同,大家可以把 Read View 理解成一个数据快照,就像相机拍照那样定格某一时刻的风景。「读提交」隔离级别是在「每个语句执行前」都会重新生成一个 Read View,「可重复读」隔离级别是「启动事务时」生成一个 Read View,然后整个事务期间都在用这个 ReadView.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值