从事务到隔离级别

本文探讨了MyISAM和InnoDB引擎的区别,重点在于事务处理能力。MyISAM适合大量SELECT查询且不涉及事务的应用,而InnoDB提供ACID事务支持。解释了事务隔离级别和其解决的问题,如脏读、不可重复读和幻读。
摘要由CSDN通过智能技术生成

今天看事务和隔离级别时突然想起之前做的项目因为字段太多表放不下然后把表的引擎改成MyISAM,这样应该是有问题的,因为MyISAM引擎是不支持事务的,那么话说回来,MyISAM还有什么用武之地呢?

那么单从事务这一点来说,既然MyISAM不支持事务,那么它肯定是用来管理非事务表的,显然,只有查询操作不会涉及到事务的,所以从这点来说,MyISAM引擎提供高速存储和检索的能力,以及全文搜索功能,包括查询数据的个数(有专门的字段保存的数据的值),这样就容易理解多了。如果应用中需要执行大量的select查询并且不涉及到事务的操作,MyISAM将会是更好的选择。

对于InnoDB来说,事务处理是很重要的一个特性,包括ACID事务支持,增删改自然用的是InnoDB了。相对于MyISAM,自然不支持全文搜索及查询数据总行数的能力了。

然后具体到事务这一块,那么什么是事务呢?简单的说,事务是指一组数据的操作,要么全部成功,要么全部失败,只要有一步失败就会回滚所有操作。

事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)四个特性,简称 ACID,缺一不可。今天要说的就是隔离性

事务隔离级别

SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:

  1. 读未提交(READ UNCOMMITTED)
  2. 读已提交 (READ COMMITTED)
  3. 可重复读 (REPEATABLE READ)
  4. 串行化 (SERIALIZABLE)

事务隔离其实就是为了解决脏读、不可重复读、幻读这几个问题:

img

只有串行化的隔离级别解决了全部这 3 个问题,其他的 3 个隔离级别都有缺陷。

脏读

脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了不一定最终存在的数据,这就是脏读。

不可重复读

对比可重复读,不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常针对数据**更新(UPDATE)**操作。

可重复读

可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的。通常针对数据**更新(UPDATE)**操作。

幻读

幻读是针对数据**插入(INSERT)**操作来说的。假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现好像刚刚的更改对于某些数据未起作用,但其实是事务B刚插入进来的,让用户感觉很魔幻,感觉出现了幻觉,这就叫幻读。

对于以上概念总是记不住,就很讨厌了。那就换个简单明了且易于记忆的说法吧。

首先要清晰的知道,事务是相对于多个线程而言的,一个线程是不会产生事务问题的,明确且了然于心这一点,我们再往下看。

从下往上推,读未提交–>读已提交–>读已提交会产生重复读取的数据不一样,即不可重复读–>所以往上是可重复读–>可重复读是针对修改数据而言的,即不会读取到另一个事务修改的数据,但是插入的数据还是会读到,所以产生了所谓的幻读–>最后再往上就是串行化了。

一个最简单的隔离级别就是读未提交了,这个最好理解,就是A线程写数据还没提交,B线程就读到了这条数据,A线程如果回滚,B线程再读,那肯定就不对了,就是常说的脏读

往上一级就是读已提交了,见文知意,就是A线程提交了数据,B线程读到了A线程提交的数据。表面上看没什么问题,但是看问题不能太表面啊,B线程就是在一个事务中啊,如果B分别在A线程提交数据前和提交数据后去读数据,那么两次读到的数据就不一样了,可能你还觉得没什么问题。一般情况下可能确实没什么问题,但是举个例子,如果你在银行柜台机上查询余额,两次查询的余额不一样,可能就有问题了。即保证不了可重复读

再往上一级就是可重复读了,简单的说,在同一个事务内,不会读到另一个事务修改后的数据,但是新插入的数据是可以读到的,这也就引发了幻读问题。

对于数据库加锁数据范围来说,分为行锁和表锁,同时,对于不同的事务隔离级别,加锁的方式是不同的,首先我们要知道,行锁其实分为以下三种:

  • LOCK_REC_NOT_GAP:单个行记录上的锁。

  • LOCK_GAP:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务

    的两次当前读,出现幻读的情况。

  • LOCK_ORDINARY:锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要

    目的是解决幻读的问题。

从上面的介绍我们可以知道,对于可重复读来说,会存在幻读的情况,即使在加锁的情况下,一个事务读取某个范围的数据,另一个事务插入数据到这个范围区间,这时候是可以获取锁的,那么在第一个事务再次执行同一条查询sql的情况下,查询结果可能和第一次查询结果不同。解决的方式就是加LOCK_GAP锁

另外,在读已提交的隔离级别下,通过加索引的字段条件查询事务查出来的结果是加了行锁的,另一个事务更新这个结果的数据是会阻塞的,这就是所谓的行锁。对于没有用到索引的sql也只会对查出的所有记录加锁,可重复读隔离级别也是一样的。

所以说,在对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,InnoDB存储引擎是不会为这个表添加表级别的

读锁或者写锁的。

所以说,在对某个表执行SELECT、INSERT、DELETE、UPDATE语句时,InnoDB存储引擎是不会为这个表添加表级别的

读锁或者写锁的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值