数据库事务ACID

数据库事务ACID

  • 数据库事务
  • ACID
    • 原子性(Atomicity)
    • 一致性(Consistency)
    • 持久性(Durability)
    • 隔离性(Isolation)
  • 并发引起的问题
    • 脏读
    • 幻读
    • 不可重复读
  • 隔离级别
    • Read Uncommitted(读取未提交内容)
    • Read Committed(读取提交内容)
    • Repeated Read(可重复读)
    • Serializable(可串行化)

数据库事务

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。


ACID

原子性(Atomicity)

原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。可以查看具体例子,可能会对这个概念理解得更好,订单生成例子。

一致性(Consistency)

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

持久性(Durability)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

隔离性(Isolation)

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

隔离性放在最后讲是有原因的,因为数据库有不同的隔离级别。我们下面先来看看事务并发会引起哪些问题。


并发引起的问题

脏读

脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据,但是这个事务拿到的数据并不正确,所以出现了脏读的情况。

例如,事务A对属性值B做了修改,在事务A修改了属性B之后,还没有提交整个事务之前,事务C读取了属性B,但是事务A发生了错误,回滚了操作,这个时候事务C读到的数据就是脏数据。

幻读

幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生:操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。

例如,事务A对表进行行计数,得出的结果是38行,同时事务B插入了2行数据,当事务A再次去进行行计数的时候,得出来的结果是40行。

不可重复读

不可重复读是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。

例如,事务A读取了属性B,值为1,还没提交事务,事务C把属性值B更改为2,事务A再次读取属性B,这个时候的值为2,显然,不能够做到重复读。

区别:不可重复读和幻读会有一点相似,但是他们是有区别的:幻读着重新增或者删除数据操作,同样的条件,读取出来的记录数不一样;不可重复读着重修改属性值,同样的条件,读取出来的属性值不一样。


隔离级别

数据库事务ACID_第1张图片
为了解决上述问题,数据库通过锁机制解决并发访问的问题。根据锁定对象不同:分为行级锁和表级锁;根据并发事务锁定的关系上看:分为共享锁定和独占锁定,共享锁定会防止独占锁定但允许其他的共享锁定。而独占锁定既防止共享锁定也防止其他独占锁定。为了更改数据,数据库必须在进行更改的行上施加行独占锁定,insert、update、delete和selsct for update语句都会隐式采用必要的行锁定。

但是直接使用锁机制管理是很复杂的,基于锁机制,数据库给用户提供了不同的事务隔离级别,只要设置了事务隔离级别,数据库就会分析事务中的sql语句然后自动选择合适的锁。

上面的表格是对隔离级别的总结,下面细品之:

Read Uncommitted(读取未提交内容)

最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。

Read Committed(读取提交内容)

只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题

前面讲了脏读例子,事务A对属性值B做了修改,在事务A修改了属性B之后,还没有提交整个事务之前,事务C读取了属性B,但是事务A发生了错误,回滚了操作,这个时候事务C读到的数据就是脏数据。

那么,这个隔离级别进行的操作就是,在事务A对属性B的值做修改后,对属性B加读锁,不允许其他事务来访问属性B的值,直到事务A提交或者回滚事务之后才对属性B解锁,这个时候其他事务才能来访问属性B。

Repeated Read(可重复读)

在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。在同一个事务内的查询都是事务开始时刻一致的。

同样,还是不可重复读的例子:事务A读取了属性B,值为1,还没提交事务,事务C把属性值B更改为2,事务A再次读取属性B,这个时候的值为2,显然,不能够做到重复读。

那么,这个隔离级别进行的操作就是,在事务A读取属性B的值后,对属性B加读写锁,直到事务A提交或者回滚事务之后才对属性B解锁,这个时候其他事务才能来访问、修改属性B。

Serializable(可串行化)

事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

幻读给的例子是:事务A对表进行行计数,得出的结果是38行,同时事务B插入了2行数据,当事务A再次去进行行计数的时候,得出来的结果是40行。

那么,这个隔离级别就是,直接对事务A操作的表进行加锁,其他事务就不能操作这个被加锁的表,直到事务A提交或回滚。

事务的隔离级别和数据库并发性是成反比的,隔离级别越高,并发性越低。

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