深入浅出Mysql 第三期

你绕不过的坎:事务

探究技术的本质,享受学习的乐趣!今天我们来聊聊事务,任何东西,存在就有其道理,事务也不例外,那么为什么会存在事务呢?我们不妨从你已经听烂了的ACID说起,如果你忘记了什么是ACID,那么我来带你回顾一下

  1. A 原子性
  2. C 一致性
  3. I 隔离性
  4. D 持久性

这四个统称为事务的特性,但是这四个并不是同一个级别的概念,在我看来,一致性是事务的目的,保证原子性,持久性以及隔离性是手段。如此,我们就可以回答开篇提出的问题,为什么会存在事务,因为需要解决数据库数据一致性的问题,即数据符合预期。那么究竟哪些情况影响到了数据的一致性呢?我认为有两种,一个经常被拿来举例的例子就是转账,比如用户A给用户B转账,这个业务至少需要两步,用户A的余额减去一个值,用户B的余额加上一个值,如果用户A的值成功修改后,这个时候数据库崩溃了,那么就出现了数据不一致的情况,即没有符合预期。出现这种情况,是因为转账这个过程存在中间态,为了解决这个状态我们就需要保证事务的原子性,当然因为数据库具有持久性的特点,所以保证原子性的同时也必须保证持久性。这样似乎就保证了数据的一致性了,那为什么还需要保证事务的隔离性呢?隔离性与并发有关系,想象一个这样的场景,用户A给用户B转账,用户C也给用户B转账。即使我们保证了转账的原子性操作,但是用户B的余额存在数据竞争,只要存在数据竞争就会出现并发问题,而出现并发问题,最直接的解决办法就是加锁。事实上,隔离性在底层就是这样实现的。如果你了解过隔离性,你就一定知道一个隔离级别这个事情。之所以有隔离级别,其实就是一致性与性能的妥协,反应在实现上就是锁的粒度问题。关系型数据库都有这四种隔离级别

  1. 串行化
  2. 可重复读
  3. 读已提交
  4. 读未提交

这里不详细解释,一致性从上到下在减弱,性能从上到下在增强。这里从SQL的规范简单介绍一下不同隔离级别下锁的粒度,但是对应到具体的数据库,比如Mysql,在只读事务与写事务存在并发的时候,会使用MVCC,这类无锁算法提高性能,这个后面说。

针对串行化而言,就是多个事务只能串行执行,这个如果是加锁实现的话,一定是互斥锁。

针对可重复读而言,在每个事务中,在执行SQL语句的时候,就会开始加锁,不过这个锁是读写锁,根据SQL语句的类型加对应的锁,比如是查询操作就加读锁,是写操作就加写锁。但是释放锁的时机很特殊,即事务结束时释放,而不是执行完对应的SQL语句就释放。这样就实现了可重复读。但是可重复读存在一个问题,那就是幻读,之所以会幻读,就是在事务A执行过程中,事务B进行了增加记录的操作,而后事务A使用范围查询的时候就会读到这个新增的记录。

针对读已提交而言,就是在一个事务中,可以看到其他事务已经提交修改的数据。这个的加锁过程是这样的,针对写操作,同样是执行写操作的SQL语句时加锁,直到事务结束释放锁。而针对读操作就是执行读操作的SQL语句时加锁,执行完毕后解锁。正因如此,所以会出现不可重复读。

针对读未提交,就是在一个事务中,可以看到其他事务修改了但是没有提交的数据。这个的加锁过程是这样的,针对写操作和读已提交一样,但是针对读操作,是不加锁的读。比如事务A在进行写操作,那么就会加写锁,而写锁和读锁互斥,但是读未提交直接不加锁读,这样就肯定读到了脏数据,也被叫做脏读。

需要说明的是,针对隔离级别加锁的过程,是参照SQL规范来做的解释,对应到数据库就不一定了。比如Mysql,就会使用MVCC进行优化,MVCC 也叫多版本并发控制。它的核心思路是以空间换时间,你只需要知道使用了MVCC,那么一条记录就会对应多个版本。那么并发的事务可以基于这些版本进行操作,就间接的没有了数据竞争,没有竞争就没有伤害,就不存在并发的一致性问题了。有关MVCC更加详细的内容,我后面会详细展开聊聊,今天就到这里,我们下期见。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值