事务基础知识

文章目录

  • 1. 事务的ACID
  • 2. 事务隔离级别
  • 2.1 数据并发问题
    • 2.2 MySQL中的四种隔离级别

1. 事务的ACID

  • 原子性(atomicity):
    原子性是指事务是一个不可分割的工作单位,要么全部提交,要么全部失败回滚。
  • 一致性(consistency):
    一致性是指事务执行前后,数据从一个合法性状态变换到另外一个合法性状态。这种状态是语义上的而不是语法上的,跟具体的业务有关
    举例:
    A账户有200元,转账300元出去,此时A账户余额为-100元。你自然就发现了此时数据是不一致的,为什么呢?因为你定义了一个状态,余额这列必须>=0。
    举例2:A账户200元,转账50元给B账户,A账户的钱扣了,但是B账户因为各种意外,余额并没有增加。你也知道此时数据是不一致的,为什么呢?因为你定义了一个状态,要求A+B的总余额必须不变。
    举例3:在数据表中我们将姓名字段设置为 唯一性约束,这时当事务进行提交或者事务发生回滚的时候,如果数据表中的姓名不唯一,就破坏了事务的一致性要求。
  • 隔离型(isolation):
    事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的并发执行的各个事务之间不能互相干扰。(通俗讲:一个事务对一张表中的记录执行操作,另一个事务不允许对这个记录操作)
  • 持久性(durability):
    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
    持久性是通过事务日志来保证的。日志包括了redo日志和undo日志。当我们通过事务对数据进行修改的时候,首先会将数据库的变化信息记录到redo日志中,然后再对数据库中对应的行进行修改。这样做的好处是,即使数据库系统崩溃,数据库重启后也能找到没有更新到数据库系统中的redo日志,重新执行,从而使事务具有持久性

2. 事务隔离级别

2.1 数据并发问题

脏写:一个事务已经commit了,但是由于另一个事务回滚了,导致没写进去。

脏读:一个事务读取到已经被另一个事务更新但是还没有提交的字段,之后若这个事务回滚了,读到的就是临时的数据,出现了脏读。

不可重复读:一个事务先读取了一个字段,另一个事务更新了字段并且commit了,之后原来事务再读同一个字段发现两次读取得数据不一致

幻读:一个事务从一个表中读取出字段,另一个事务对这个表插入了一些行,原事务再次读取这个表发现读到得行变多了。

2.2 MySQL中的四种隔离级别

READ-UNCOMMITTED:读未提交
READ-COMMITTED(Oracle默认级别):读已提交
REPEATABLE-READ(Mysql默认级别):重复读
SERIALIZABLE:串行化
事务基础知识_第1张图片

Mysql下幻读解析:幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些: select某记录是否存在,不存在,准备插入此记录,但执行insert时发现此记录已存在,无法插入,此时就发生了幻读。

所以MysQL的幻读并非什么读取两次返回结果集不同,而是事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测读获取到的数据如同鬼影一般。

其实RR也是可以避免幻读的,通过对select操作手动加 行X锁(独占锁)(SELEC …FOR UPDATE这也正是 SERIALIZABLE隔离级别下会隐式为你做的事情)。同时,即便当前记录不存在,比如id = 3是不存在的,当前事务也会获得一把记录锁(因为InnoDB的行锁锁定的是索引,故记录实体存在与否没关系,存在就加 行X锁,不存在就加 间隙锁 ),其他事务则无法插入此索引的记录,故杜绝了幻读。 在 SERIALIZABLE隔离级别下,step1执行时是会隐式的添加 行(X)锁/ gap(x)锁的,从而step2 会被阻塞,step3 会正常执行,待事务1提交后,事务2才能继续执行(主键冲突执行失败),对于事务1来说业务是正确的,成功的阻塞扼杀了扰乱业务的事务2,对于事务1来说他前期读取的结果是可以支撑其后续业务的。
所以MySQL的幻读并非什么读取两次返回结果集不同,而是事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测读获取到的数据如同鬼影一般。

你可能感兴趣的:(数据库,数据库,oracle)