MySql中的事务简单介绍

事务是什么?事务是指在数据库中按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以有某种数据库程序自动执行。简单来说,事务就是逻辑上要嘛都执行要嘛都不执行的一组操作。

目录

1. 事务的特性

2. 并发事务带来的问题

2.1 并发事务带来的数据库读取问题

2.2 脏读、幻读、不可重复读之间的区别

2.3 通过事务隔离级别解决这些问题的方案

2.3.1 四种事务隔离级别的测试

2.4 事务隔离级别的实现方案

2.5 MySql中的锁和MVCC版本控制

2.5.1 MySql中的锁

2.5.2 乐观锁和悲观锁

2.5.3 MySql的MVCC机制

2.5.4 当前都和快照读的区别


1. 事务的特性

事务总共有四个特性,分别为原子性,一致性,隔离性,持久性,接下来我们分别介绍这四个特性。

原子性(Actomicity):事务是一个完整的操作,事务的各步操作是不可分的(原子的),要么都执行,要么都不执行。这也很好理解,对于银行转账这个事务,从转钱方扣除钱数,以及金钱的转入方账户增加钱数这两项操作共同构成了事务。若是事务不具有原子性,即转出方操作成功,转入方操作失败。或者是转出方操作失败,转入方操作成功。这会对双方账户金额造成很大的影响,所以数据库的操作需要满足原子性。

一致性(Consistency):执行事务前后,数据保持一致。事务的一致性是指对于某项操作对数据库的处理,要么处理成功,要么处理失败,数据库中的数据只能从一个一致性状态到另外一个一致性状态。只有保证了事务的持久性、原子性、隔离性之后,事务的一致性才能得到保障。

隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务干扰,各并发事务之间数据库是独立的。事务的隔离性保证并发执行的操作处理的不是同一个数据库的数据,而是其他并发操作处理结束后的数据库。事务的隔离性是通过锁机制和MVCC机制实现的。

持久性(Durability):当事务被提交后,即使数据库出现故障,该事务对数据库的处理应该是得到保存的。事务的持久性保证事务提交后,该事务所更改的数据会被写到磁盘做持久化处理。

2. 并发事务带来的问题

并发事务会带来很多问题,包括脏读,幻读,不可重复读这几个问题。我们可以通过设置事务隔离级别避免并发事务带来的这几个问题。

2.1 并发事务带来的数据库读取问题

脏读:一个事务读取数据并对数据进行了修改,这个修改对其他事务来说是可见的,即使当前事务没有提交。这时另外一个事务读取了这个还未提交的数据,但第一个事务突然回滚,造成了第二个事务读取的数据是错误的,是一个数据库中不存在的数据。所以就被叫做脏读。

幻读:一个事务读取了一些数据,接着另外一个并发事务插入了一些数据。此时第一个事务在后续的查询时,发现查询出来的数据多了一些原本不存在的记录,就好像发生了幻觉一样,所以叫做幻读。

不可重复读:指的是一个事务多次读取同一个数据。此时另一个并发事务也访问了该数据,并对该数据进行修改。第一个事务发现接下访问的数据与之前访问的数据不一样。这就是不可重复读。

2.2 脏读、幻读、不可重复读之间的区别

脏读和不可重复读之间的区别:脏读偏重于读取了还未提交的数据,而原本准备提交的事务回滚了导致读取数据错误。而不可重复读不能读取还未提交的数据,它是因为多次读取同一个数据,期间因为其他事务的修改导致读取数据错误。

脏读和幻读的区别:脏读是读取了还未提交的事务,导致数据出现错误,幻读是读取了已经提交的事务,但是因为其他事务对数据库进行了增加的操作,导致读取了一些原本不存在的数据像是产生了幻觉。

幻读和不可重复读的区别:不可重复读的重点是内容修改或者记录减少,比如多次读取一条数据记录发现其中某些记录的值被更改。而幻读侧重于多次执行同一条查询语句时,发现查到的记录增加了。简单来说,不可重复读的重点是update和delete,而幻读的重点是insert。

总结:脏读读取还未提交的数据,其的隔离级别最低。幻读和不可重复读都是读取已经提交的事务,但幻读牵扯到查询,所以对于整个数据库都的数据都需要考虑到,所以相对于不可重复读,解决幻读需要的隔离级别更高。

2.3 通过事务隔离级别解决这些问题的方案

事务的隔离级别可以分为4个,可以解决并发事务造成的三种问题,接下来介绍四种事务隔离级别。

读未提交(READ-UNCOMMITTED):最低的隔离级别,脏读就发生在这个隔离级别,读取还未提交的事务。

读已提交(READ-COMMITTED):该隔离级别可以解决脏读的问题,事务并不能读取还未提交的数据了,但是幻读和不可重复读的问题仍然存在。

可重复读(REPEATABLE-READ): 该隔离级别通过ReadView实现可重复读,对于事务的读取设置版本记录,当一个事务第二次去同一个数据时,只会读取对应版本的数据,其他事务更新的数据并不会被读取到。但是这种方法只是维持数据库中的某一些数据,仍然不能解决幻读的问题,因为幻读问题主要是由数据的插入引起的。Mysql的默认隔离级别也是这个隔离级别。

可串行化(SERIALIZABLE): 该隔离级别完全服从ACID。将所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,有效保护了整个数据库的数据。该隔离级别可以防止脏读、不可重复读以及幻读。

2.3.1 四种事务隔离级别的测试

首先我们登录两个MySql的客户端模拟并发事务。

我们接下来查询数据库默认的事务隔离级别,然后将事务的自动提交关闭,选择使用手动提交的方式,然后再将数据库的事务隔离级别设置为读未提交(READ-UNCOMMITTED),测试在这中隔离级别的情况下出现的脏读的现象。

 我们在一个客户端更新数据库中的数据,在未提交的情况下用另外一个客户端查询数据,我们可以看到如下图所示,发生了脏读的现象。

 

 如果我们将事务的隔离级别设置为READ-COMMITTED将不会出现这样的问题,如下图所示:

2.4 事务隔离级别的实现方案

MySql的隔离级别是通过锁和MVCC机制共同实现的。SERIALIZABLE隔离级别是通过锁来实现的,REPEATABLE-READ 在当前读情况下需要使用加锁读来保证不会出现幻读。而READ-COMMITTED 和 REPEATABLE-READ 隔离级别是基于 MVCC 实现的。

2.5 MySql中的锁和MVCC版本控制

2.5.1 MySql中的锁

MySql的锁是一种常见的并发事务的控制方式,分为表级锁和行级锁。表级锁是锁定粒度较大的一种锁,对当前操作的整张表加锁。行级锁是锁定粒度较小的一种锁,是针对索引字段加的锁

serializable序列化隔离级别,是使用表级锁完成的。InnoDB有记录所、间隙锁、临键锁三种行级锁。REPEATABLE-READ隔离级别默认使用的是Next-Key Lock。但是如果操作的索引是唯一索引或主键,InnOB会对Next-Key Lock进行优化,将其降级未Record Lock,即仅锁住索引本身,而不是范围。

记录锁(Record Lock):也被称为记录锁,属于单个记录上的锁。

间隙锁(Gap Lock): 锁定一个范围,不包括记录本身。

临键锁(Next-Key Lock): Record Lock+Gap Lock,锁定一个范围,包括记录本身,主要是为了解决幻读问题。记录锁只能锁住已经存在的记录,为了避免插入新记录,需要依赖间隙锁。

2.5.2 乐观锁和悲观锁

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。在查询完数据的时候就把事务锁起来,直到提交事务。

乐观锁:假定不会发生并发冲突,只在提交操作时检查是否违反数据完整性,乐观锁一般会使用版本号机制实现,适用于读多写少的应用场景,这样可以提高吞吐量。

2.5.3 MySql的MVCC机制

多版本并发控制(MVCC)是一种用来解决读-写冲突的机制,通过为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照。MVCC机制可以有效解决脏读,不可重复读,幻读等事务隔离问题。

2.5.4 当前都和快照读的区别

当前读:每次读取的都是当前最新的数据,但是读的时候不允许写,写的时候不允许读。

快照读:读写不冲突,每次读取的都是快照数据。在读未提交隔离级别下,没有快照数据这一概念,怎么读都是读到最新的数据版本,不管是否提交。在读已提交的事务隔离级别下,快照是在SQL语句开始执行的时候生成的。在可重复读的事务隔离级别下,快照是在事务开始的时候生成的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值