事务并发问题和隔离级别

事务基本性质

事务有四个属性,ACID。

  • 原子性Atomicity,事务里的命令全部执行,或全部不执行,是不可分割的整体。
  • 一致性Consistency,保证操作前后数据和数据结构的一致性。
  • 隔离性Isolation,不同事物之间互补干扰。同一时间只允许一个事务请求一个数据。
  • 持久性Durability,数据更新持久化,更改时永久的。

事务的并发问题

事务并发会造成三个问题:脏读,不可重复读,幻读。

  1. 脏读:事务A读了事务B更新的数据,然后事务B回滚撤销了,事务A读取的数据就是脏读。
  2. 不可重复读:事务A读取数据num后,事务B对其修改,事务A再次读取数据num,前后不一致,这情况为不可重复读。
  3. 幻读:事务A读取数据(一张表),事务B对此表新增或删除记录,这种情况为幻读。

不可重复读和幻读的区别:一个针对一条记录的更新,一个针对表的更新。因此要解决两者,分别要用到行锁和表锁。这也就造成解决两者的隔离级别不同。

事务隔离级别

隔离级别有四个:

  1. read-uncommitted:不能解决脏读、不可重复读、幻读
  2. read-committed:解决脏读,不能解决不可重复读、幻读
  3. repeatable-read:解决脏读、不可重复读、幻读
  4. serializable:解决脏读、不可重复读、幻读

其中mysql的事务隔离级别为reapeatable-read
image

事务隔离级别四个例子

打开两个mysql进程,创建一个test表,插入简单的数据,可以在两个mysql进程都看到表内容。
image
image

read-uncommitted

两个进程mysql都要将隔离级别设置为read-uncommitted。
image

步骤:

  • 进程A开启事务读数据num为50
  • 进程B开启事务读数据num为50,修改数据为100
  • 进程A再次读数据为100
  • 进程B回滚,则进程A读取到的数据100为脏数据

进程B的情况
image

read-committed

步骤:

  • 进程A开启事务读数据num为50
  • 进程B开启事务读数据num为50,修改数据为100
  • 进程A读数据num仍然为50,并没有受到进程B事务的影响
  • 进程B提交事务,读取数据为100
  • 进程A读取数据num为100,则出现数据不可重复读现象
    image

repeatable-read

步骤:

  • 进程A开启事务读取数据num为50
  • 进程B开启事务读取数据num为50,修改数据为100
  • 进程B提交事务,读取数据num为100
  • 进程A读取数据num仍然为50,即使进程B已经提交事务,进程A并没有受到进程B的影响
  • 进程B插入一条数据
  • 进程A没有查出新增数据,没有数据幻读
  • 进程A提交事务后,查询数据num为100,并查询到新增数据
    image

serializable

步骤:

  • 进程A开启事务读取数据为100
  • 进程B开启事务读取数据为100,修改数据为50,进程B卡住

个人认为,是因为表被锁了,在等待进程A释放锁,然后进程B可以对表进行修改

小结

  • 事务隔离级别为read-committed时,写数据会锁住相应行,进程A再读时,就会读取上个版本的数据,但是会增加或删除别的记录,就会出现幻读现象。
  • 事务隔离为repeatable-read时,更新数据会锁住整张表,从而防止幻读现象。
  • 事务隔离级别为串行化时,读写数据都会锁住整张表。

在进行相关操作后,对事务的理解更加深刻。关于读取上版本,MVCC内容需要抽空去学习一下。

原文地址:https://www.cnblogs.com/chenshaowei/p/12566030.html