【数据库的三大特性】——数据库中事务,事务的隔离性,隔离级别,事务的实现

事务:

事务的四大特性:ACID

说到事务的ACID,原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

  • 原子性

    指一个事务是一个不可分割的工作单位,其中的操作要么都做,要么都不做。要么全部提交,要么全部回滚。

  • 一致性

    事务中操作的数据及状态是一致的,即写入资料的结果必须完全符合预设的规则,不会因为出现系统意外等原因导致状态的不一致。

  • 隔离性

    一个事务所操作的数据在提交之前,对其他事务的可见性设定(一般设定为不可见)

    MySQL中的隔离级别有:读未提交(Read Uncommitted)、读已提交(Read committed)、可重复读(Repeatable Read)、串行化(Serializable)。

  • 持久性

    事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。

ACID之间的关系

四种特性不是一种平等的关系:

  • 只有满足一致性,事务的结果才是正确的
  • 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还要满足隔离性,才能满足一致性。
  • 事务满足持久化是为了应对数据库崩溃的情况。

事务的隔离级别

  • 未提交读(Read Uncommitted)

会产生脏读,即使没有提交,对其他事务也是可见的

  • 提交读(read committed)

产生不可重复读,一个事务只能读取已经提交的事务所做的修改,换句话说,一个事务所做的修改在提交之前对其他事务是不可见的

  • 可重复读(repeatable read)

会出现幻读,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁(悲观锁),其它事务无法修改这些数据,就可以实现可重复读了。

但这种方法却无法锁住insert的数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读

但是MySQL、ORACLE、PostgreSQL等成熟的数据库,出于性能考虑,都是使用了以乐观锁为理论基础的MVCC(多版本并发控制)来实现,通过间隙锁(next-key locking)策略防止幻读的出现

  • 可串行化(serializable)

读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

举个例子吧:

读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出
现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

在这里插入图片描述
我们来看看在不同的隔离级别下,事务 A 会有哪些不同的返回结果,也就是图里面 V1、V2、V3 的返回值分别是什么。

  • 若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是
    结果已经被 A 看到了。因此,V2、V3 也都是 2
  • 若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A看到。所以, V3 的值也是 2。
  • 若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。
  • 若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。
隔离级别脏读不可重复读幻影读
未提交读:事务中的修改,即使没有提交,对其他事务也是可见的
提交读:一个事务只能读取到已经提交的事务所做的修改×
可重复读:保证一个事务中多次读取同样的数据结果是一样的××
可串行化:强制事务串行化(需要加锁实现)×××

锁问题

脏读

脏读指的是不同事务下,当前事务可以读取到另外事务未提交的数据。

例如:

T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。

img

不可重复读

不可重复读指的是同一事务内多次读取同一数据集合,读取到的数据是不一样的情况。

例如:

T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。

img

在 InnoDB 存储引擎中,SELECT 操作的不可重复读问题通过 MVCC 得到了解决,而 UPDATE、DELETE 的不可重复读问题是通过 Record Lock 解决的,INSERT 的不可重复读问题是通过 Next-Key Lock(Record Lock + Gap Lock)解决的。

Phantom Proble(幻影读)

The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

Phantom Proble 是指在同一事务下,连续执行两次同样的 sql 语句可能返回不同的结果,第二次的 sql 语句可能会返回之前不存在的行。

幻影读是一种特殊的不可重复读问题。

丢失更新

一个事务的更新操作会被另一个事务的更新操作所覆盖。

例如:

T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。

img

这类型问题可以通过给 SELECT 操作加上排他锁来解决,不过这可能会引入性能问题,具体使用要视业务场景而定。

参考:敖丙

posted @ 2021-05-21 23:22  your_棒棒糖  阅读(159)  评论(0编辑  收藏  举报