事务四大特性和隔离级别总结

基本上是这个公众号文章里的: https://mp.weixin.qq.com/s/uMBPfM7zx0Rp_brP4cnKaA
MySQL 持久化保障机制-redo 日志
https://mp.weixin.qq.com/s/vmB7Gsr9N3ZfF805wy6eHw

事务四大特性:

ACID
原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)

A:原子性(Atomicity)

定义

一次操作是不可分割的,要么全部成功,要么全部失败。比如我们的转账操作,不允许出款方成功,收款方失败这种情况,要么都成功,要么多失败,不可能出现中间状态。

实现

InnoDB 引擎使用 undo log(归滚日志)来保证原子性操作,你对数据库的每一条数据的改动(INSERT、DELETE、UPDATE)都会被记录到 undo log 中,比如以下这些操作:

  • 你插入一条记录时,至少要把这条记录的主键值记下来,之后回滚的时候只需要把这个主键值对应的记录删掉就好了。
  • 你删除了一条记录,至少要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了。
  • 你修改了一条记录,至少要把修改这条记录前的旧值都记录下来,这样之后回滚时再把这条记录更新为旧值就好了。

当事务执行失败或者调用了 rollback 方法时,就会触发回滚事件,利用 undo log 中记录将数据回滚到修改之前的样子。

C:一致性(Consistency)

定义

一致性简单一点说就是数据执行前后都要处于一种合法的状态,比如身份证号不能重复,性别只能是男或者女,高考的分数只能在0~750之间,红绿灯只有3种颜色,房价不能为负的等等, 只有符合这些约束的数据才是有效的,比如有个小孩儿跟你说他高考考了1000分,你一听就知道他胡扯呢。数据库世界只是现实世界的一个映射,现实世界中存在的约束当然也要在数据库世界中有所体现。如果数据库中的数据全部符合现实世界中的约束(all defined rules),我们说这些数据就是一致的,或者说符合一致性的。

实现

要保证数据库的数据一致性,要在以下两个方面做努力:

  • 利用数据库的一些特性来保证部分一致性需求:比如声明某个列为NOT NULL 来拒绝NULL值得插入等。
  • 绝大部分还是需要我们程序员在编写业务代码得时候来保证

I:隔离性(Isolation)

定义

多个事务并发执行的时候,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

隔离性可能引发的问题,和隔离级别

在下面

实现

InnoDB 引擎是如何保证隔离性的?利用锁和 MVCC 机制。这里简单的介绍一下 MVCC 机制,也叫多版本并发控制,在使用 READ COMMITTD、REPEATABLE READ 这两种隔离级别的事务下,每条记录在更新的时候都会同时记录一条回滚操作,就会形成一个版本链,在执行普通的 SELECT 操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。

D:持久性(Durability)

定义

事务一旦提交,它对数据库的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

实现

要保证持久性很简单,就是每次事务提交的时候,都将数据刷磁盘上,这样一定保证了安全性,但是要知道如果每次事务提交都将数据写入到磁盘的话,频繁的 IO 操作,成本太高,数据库的性能极低,所以这种方式不可取。

InnoDB 引擎是怎么解决的?InnoDB 引擎引入了一个中间层来解决这个持久性的问题,我们把这个叫做 redo log(归档日志)。

为什么要引入 redo log?redo log 可以保证持久化又可以保证数据库的性能,相比于直接刷盘,redo log 有以下两个优势:

  • redo log体积小,毕竟只记录了哪一页修改了啥,因此体积小,刷盘快。
  • redo log是一直往末尾进行追加,属于顺序IO。效率显然比随机IO来的快。

InnoDB 引擎是怎么做的?当有一条记录需要更新的时候,InnoDB 引擎就会先把记录写到 redo log 里面,并更新内存,这个时候更新就算完成了。当数据库宕机重启的时候,会将 redo log 中的内容恢复到数据库中,再根据 undo log和 binlog 内容决定回滚数据还是提交数据。

隔离性可能引发的问题,和隔离级别

事务的隔离性:多个事务并发执行的时候,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。(像是多线程的概念)
而隔离性就可能引起:脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)等问题,(就是线程安全问题)

问题

  • 脏读:
    所谓的脏读,其实就是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。
    (就是读到的数据可能是 要修改但没改成功的 假数据,读到了事务的日志里的数据。read uncommitted会引发的问题)

  • 不可重复读:
    事务A首先读取了一条数据,然后执行逻辑的时候,事务B将这条数据改变了,然后事务A再次读取的时候,发现数据跟第一次读到的不匹配了,就是所谓的不可重复读了。
    (就是在同一事务中第二次读取的时候,被别的事务把改数据修改删除了,跟多线程的线程安全问题一样,所以就可以加同步锁啊,就是这条数据在读取的时候,不能让修改的事务对这条数据进行操作,不就解决了吗。当然不会这么简单,只是这么理解,这就是repeatable read解决的问题)

  • 幻读:
    事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。
    (只能用序列化级别解决:因为(repeatable read)行级锁只能锁一条数据,添加的话它是不会操作锁得这条数据的,所以就会产生两次数据条数不一样(幻读)。如果要防止在读的时候添加数据,那就要监控整张表了,所以就要添加表级锁,在这个事务运行时,所有对表的操作的事务都不可以进来(Serializable )只是理解,没有这么简单)

注意:不可重复读和幻读的区别是:

前者是指在一个事务过程中读到了另一个事务已经提交事务的 更改数据修改或删除);
后者是指在一个事务过程中读到了另一个事务已经提交事务的 新增数据

对于这两种问题解决采用不同的办法:
解决不可重复读,只需对操作的数据添加行级锁,防止操作中的数据发生变化;(行级锁锁不住添加数据,就可能导致两次查询数目不一致)
解决幻读,往往需要添加表级锁,将整张表锁定,防止新增数据(oracle采用多版本数据的方式实现)。
在这里插入图片描述

图片来源: http://blog.itpub.net/26736162/viewspace-2638951/

隔离级别:

SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable):

  • 读未提交(read uncommitted):一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交(read committed):一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读(repeatable read)保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。(给数据加行级锁,读的时候不能更改数据(修改或删除),修改的时候不能读)
    但是,在测试时,是可以修改成功的,只是自己读的还是修改之前的数据。所以猜测:是在本次事务对数据加行级锁与其他事务无关,隔离性
  • 序列化(serializable): 顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。**在本次事务中加 表锁。**锁住整个表。

总结

隔离级别越高,效率越慢。
表格从上到下级别越来越高,mysql默认是repeatable read级别

隔离级别/问题脏读不可重复读幻读
读未提交(read uncommitted)可能可能可能
读提交(read committed)不可能可能可能
可重复读 (repeatable read)不可能不可能可能
串行化(serializable)不可能不可能不可能

mysql命令

命令含义
select version()查看MySQL版本
SELECT @@tx_isolation查看MySQL隔离级别
set session transaction isolation level 隔离级别名会话层面设置隔离级别
start transaction开启事务
commit提交事务
rollback回滚事务
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值