数据库的ACID特性及事务控制

1、数据库ACID特性:

数据库的ACID特性是数据库事务正确执行的四个基本要素的缩写。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。一个支持事务的数据库,必须要具有这四种特性。

  • 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,是单个事务级别的概念,其实现是基于日志的UNDO机制(系统崩溃重启或者回滚时撤销所有部分执行但尚未提交的操作)。
  • 一致性是指事务必须始终保持系统处于一致的状态,其它的三个特性都为了保证一致性而存在的。
  • 隔离性是指多个并发事务之间要相互隔离,一个事务不能被其他并发事务的操作所干扰,通过事务隔离实现。
  • 持久性是指在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚,其实现是基于日志的REDO机制(系统崩溃重启时将所有已经提交的操作写入磁盘)。

2、事务并发控制异常

  • 脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据,例如第一个事务对一个表中的数据进行了修改。在未提交时,第二个事务读取了修改的数据。而第一个事务由于各种原因未提交,第二个事务就发生了脏读。
  • 不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
  • 幻读是指当事务不独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,操作第一个事务的用户之后会发现表中还存在没有修改的数据行,就好象发生了幻觉一样。幻读和不可重复读的区别是不可重复读查询的都是同一个数据项,重点在于update和delete,而幻读针对的是一批数据整体,重点在于insert。
  • 第一类丢失更新是指由于回滚造成的更新丢失,即事务失败回滚时覆盖掉另一个事务的更新,又称回滚丢失。
  • 第二类丢失更新是指由于更新被其他事务覆盖导致的更新丢失,即后提交事务覆盖掉先提交事务的更新,也可以叫覆盖丢失。

3、事务隔离级别

数据库的隔离级别实现一般是通过数据库锁实现的,其级别由低到高分为读未提交、读已提交、可重复读和串行化四级。级别越高,执行效率就越低,在MySQL数据库中默认的隔离级别为可重复读,在Oracle中只支持串行化和读已提交两种级别,其中默认为读已提交。

  • 读未提交(Read Uncommitted):该隔离级别指即使一个事务的更新语句没有提交,但是别的事务可以读到这个改变,几种异常情况都可能出现。极易出错,没有安全性可言,基本不会使用。
  • 读已提交(Read Committed):该隔离级别指一个事务只能看到其他事务的已经提交的更新,看不到未提交的更新,消除了脏读和第一类丢失更新,这是大多数数据库的默认隔离级别,如Oracle,Sqlserver。
  • 可重复读(Repeatable Read):该隔离级别指一个事务中进行两次或多次同样的对于数据内容的查询,得到的结果是一样的,但不保证对于数据条数的查询是一样的,只要存在读改行数据就禁止写,消除了不可重复读和第二类更新丢失,这是Mysql数据库的默认隔离级别。
  • 串行化(Serializable):意思是说这个事务执行的时候不允许别的事务并发执行.完全串行化的读,只要存在读就禁止写,但可以同时读,消除了幻读。这是事务隔离的最高级别,虽然最安全最省心,但是效率太低,一般不会用。
级别\异常 脏读 不可重复读 幻读 第一类更新丢失 第二类丢失更新
读未提交 Y Y Y Y Y
读已提交 N Y Y N Y
可重复读 N N Y N N
串行化 N N N N N

4、数据库的锁机制

数据库锁一般可以分为两类:悲观锁和乐观锁。悲观锁一般就是我们通常说的数据库锁机制,乐观锁一般是指用户自己实现的一种锁机制,比如hibernate实现的乐观锁甚至编程语言也有乐观锁的思想的应用。

  • 悲观锁:对于数据被外界修改持保守态度,认为数据随时会修改,所以整个数据处理中需要将数据加锁,一般都是依靠关系数据库提供的锁机制。悲观锁按照作用范围分为行锁和表锁,按照使用性质划分则如下表:

    锁类型 锁特点
    共享锁(S锁) 又称读锁,事务A对对象T加S锁,其他事务也只能对T加S锁,即多个事务可以同时读,但不能有写操作,直到A释放S锁。
    排它锁(X锁) 又称写锁,事务A对对象T加X锁以后,其他事务不能对T加任何锁,只有事务A可以读写对象T直到A释放X锁。
    更新锁(U锁) 允许其他事务读,但不允许再施加U锁或X锁;当被读取的对象将要被更新时,则升级为X锁,主要是用来防止共享锁导致的死锁。因为使用共享锁修改数据时,首先获得共享锁读取数据,然后升级为排它锁执行修改操作。这样当两个或多个事务同时对一个对象申请了共享锁再修改数据时会一直等待对方释放锁导致死锁。
  • 乐观锁:对于数据被外界修改持乐观态度,认为操作数据时没有事务修改它,所以不去加锁,但在更新的时候会去判断在此期间数据有没有被修改,需要用户自己去实现。它可以提高吞吐量,但也增加了复杂度,也带来了额外的风险。乐观锁可以通过版本行或者时间戳等实现,也可以利用数据库已有字段实现。

参考

  • https://www.cnblogs.com/fjdingsd/p/5273008.html
  • https://www.cnblogs.com/ismallboy/p/5574006.html
  • https://blog.csdn.net/aluomaidi/article/details/52460844
  • https://www.cnblogs.com/sheseido/p/5038562.html

你可能感兴趣的:(数据库的ACID特性及事务控制)