并发事务下,不同隔离级别可能出现的问题

并发事务下,不同隔离级别可能出现的问题

  • 1、事务的 ACID
  • 2、并发事务下,不同隔离级别可能出现的问题
    • 2.1、脏写
    • 2.2、脏读
    • 2.3、不可重复读
    • 2.4、幻读
  • 3、SQL 中的四种隔离级别

1、事务的 ACID

 

    1. 原子性(Atomicity):原子性意味着事务是一个不可分割的最小工作单元,事务内的操作要么全部完成,要么全部不完成,不可能停滞在中间某个环节。也就是说,事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
    1. 一致性(Consistency):指事务必须使数据库从一个合法性状态,变换到另一个合法性状态。这里的状态是指数据满足完整性约束(如主键约束、外键约束、检查约束等)的状态,这里说的状态是语义上的,和具体业务有关。一致性就是保证事务执行后,数据库中的数据仍然是有意义的。
    1. 隔离性(Isolation):指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
    1. 持久性(Durability):一旦事务提交,则其结果永久保存在数据库中。即使系统发生故障,数据库也能将数据恢复到事务成功执行的状态。持久性是通过事务日志保证的。

并发事务下,不同隔离级别可能出现的问题_第1张图片

数据库事务的状态通常包括以下几种:

  1. 活动状态(Active):事务正在执行,尚未提交或回滚。
  2. 部分提交状态(Partially Committed):事务中的一部分操作已经完成并提交,但其他操作还在执行中。
  3. 失败状态(Failed):事务执行失败,需要进行回滚操作。
  4. 成功状态(Succeeded):事务执行成功,所有的操作都已经提交。
  5. 中止状态(Aborted):事务在执行过程中被中断,比如由于系统故障或者数据库故障。

 

2、并发事务下,不同隔离级别可能出现的问题

 
并发执行事务过程中,不同隔离级别下可能出现的问题

重要程度排序脏写 > 脏读 > 不可重复读 > 幻读

 

2.1、脏写

 
对于两个事务A、B,如果事务A 修改了 另一个未提交事务B 修改过的数据,那就是发生了脏写。以下示例,事务A已经提交成功,但是事务B回滚了,最终 no=1 的数据没有任何变化。

发生时间编号 事务 A 事务 B
begin;
begin;
update tb_table set name = ‘对对对’ where no = 1;
update tb_table set name = ‘错错错’ where no = 1;
commit;
rollback;

 

2.2、脏读

 
举例:对于两个事务A、B,事务A读取了已经被事务B 更新未被提交的数据,之后事务B 回滚了,事务A读取的内容就是临时且无效的。

发生时间编号 事务 A 事务 B
begin;
begin;
update tb_table set name = ‘对对对’ where no = 1;
select name from tb_table where no = 1; (发生脏读,这里读到name = ‘对对对’)
commit;
rollback;

 

2.3、不可重复读

 
举例:对于两个事务A、B,事务A读取了一个字段,然后事务B 更新了该字段,之后事务A再次读取同一个字段,值就不同了,这种情况就是不可重复读。

发生时间编号 事务 A 事务 B
begin;
select name from tb_table where no = 1; (这里读到name = ‘原始数据’)
begin;
update tb_table set name = ‘对对对’ where no = 1;
commit
select name from tb_table where no = 1; (发生不可重复读,这里读到name = ‘对对对’)
commit;

 

2.4、幻读

 
       对于两个事务A、B,事务A从一个表中读取了一个字段,然后事务B 在该表中插入了一些新的行。之后事务A 再次读取同一个表,就会多出几行数据,这就是幻读。幻读侧重的方面是某一次的select 操作得到的结果,所表征的数据状态无法支撑后续的业务操作。对于MySQL而言,幻读是事务在插入事先检测不存在的记录时,发现这条数据已经存在了,无法支撑后续的插入操作。

发生时间编号 事务 A 事务 B
begin;
select * from tb_table where no > 1; (这里读到了2条数据)
begin;
insert into tb_table values(4,‘测试’);
commit
select * from tb_table where no > 1; (发生幻读,这里读到了3条数据)
commit;

 
说明:

  • 以上第④步,如果删掉了id=2 的数据,导致第⑥步只读到1条数据,这种情况不算幻读。幻读强调的是一个事务按照某个相同条件多次读取记录时,后读取时读到了之前没有读到的记录
  • 对于先前已经读到的记录,之后又读取不到,这相当于对每条记录都发生了不可重复读的现象。

3、SQL 中的四种隔离级别

 
隔离级别越低,并发问题发生的就越多。 SQL 标准 中设立的 4 个隔离级别:

  • READ UNCOMMITTED读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读

  • READ COMMITTED读已提交,一个事务只能看到已经提交事务所做的改变。这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。可以避免脏读,但是**不可避免 不可重复读、幻读**。

  • REPEATABLE READ 可重复读(MySQL默认隔离级别),事务A 在读到一条数据后,此时事务B对该数据进行修改并提交,那么事务A再读该数据,读到的还是原来的内容。可以避免脏读、不可重复读,但是**不可避免幻读**。重点MySQL 在可重复读级别下,是可以禁止幻读的。

  • SERIALIZABLE可串行化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作。可以避免所有的并发问题,但是**性能十分低下能避免脏读、不可重复读、幻读**。

不同的数据库厂商,对SQL标准中规定的四种隔离级别支持不一样。以下是 SQL 标准中规定(注意:这里不是 MySQL),对不同隔离级别下,并发事务可以发生不同严重程度的问题:

隔离级别 脏读 不可重复度 幻读 加锁读
READ UNCOMMITTED 发生 发生 发生 避免
READ COMMITTED 避免 发生 发生 避免
REPEATABLE READ 避免 避免 发生 避免
SERIALIZABLE 避免 避免 避免 发生

 
 
 
 
 
 
 
.

你可能感兴趣的:(MySQL,隔离级别,脏读,脏写,幻读,可重复读,CAID,隔离性)