MySQL事务和隔离级别

一、什么是MySQL事务?

MySQL的事务可以通俗理解为一个或多个SQL语句组成的单元,在这个单元中,每个SQL的语句都是相互依赖的,一个SQL语句执行失败,那么整个单元的SQL语句都不会成功,都会回到最开始执行的状态,也就说要么全部成功,要么全部失败。

二、MySQL事务的四个特性(ACID)

1.原子性(Atomicity):指事务是一个不可分割的最小工作单位,事务中的操作只有都发生和都不发生两种情况

2.一致性(Consistency)事务必须使数据库从一个一致状态变换到另外一个一致状态,举一个例子,小明花费100元从淘宝购买一双鞋,这个事务就是让小明账户上减去100元,商家账户上加上100元;一致性是指其他视角上看到的情况是要么是小明还没购买鞋,商家账户没有增加100元,要么商家已经成功收到小明的购买金,小明也得到了鞋子。而对于小明少了100元,商家还没加上100元这个中间状态是不存在的。

3. 持久性(Durability)事务提交之后对数据的修改是永久性的, 即使数据库宕机也不会丢失。可通过MySQL中重做日志(redo log)来保证。当有一条记录需要修改的时候,MySQL会通过支持事务的存储引擎InnoDB把这条记录提前写入日志中,在发生故障,数据库恢复之后再进行回滚(数据恢复操作,恢复到之前的状态)。
4.隔离性(Isolation):指一个数据库服务器, 同时执行多个事务操作的时候, 每一个事务的执行不能被其他事务所干扰。如果隔离性越高, 就意味着事务之间的并发程度越低, 执行效率越慢, 但是数据准确性越高。如果隔离性越低, 就意味着事务之间的并发程度越高, 执行效率越快, 但是数据准确性越低

三、事务并发异常

在生产环境下,数据库会出现大规模并发请求的情况,如果没有设置好事务的隔离级别,可能会出现脏读(Dirty Read), 幻读(Phantom Read)和不可重复读(Unrepeatable Read)

1.脏读(Dirty Read)

一个事务读取到了另外一个事务没有提交的数据,举个例子,对于两个事务T1,T2,T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的。
如张三刚写完一道leetcode代码题,此时李四不会做,走过来看张三的思路,此时张三还未进行提交,不知道正确与否,李四记住了的张三写的代码题,转身回去自己试一试,而张三发现思路不对,写错了,删除了刚刚写的代码,此时李四记住的代码就是一段错误的代码。
这里张三和李四可以看作为两个事务,这两个事务没有限制,就会出现脏读问题。
如何解决“脏读问题”?
降低事务的并发性,提高隔离性,这个比方来说,就是给张三写代码这个操作“加限制”,也就是“读加锁”,张三和李四约定好,只有在张三写完并成功提交完毕之后,李四才能过来进行查看。
这个“写加锁”的操作,降低了事务的并发性,降低了数据库的效率,但提高了隔离性,提高了数据的准确性

2.不可重复读(Unrepeatable Read)

同一个事务在两次读取同一个数据的时候,两次读取到的结果不一致,举个例子,对于事务T1,T2,T1正在读取T2已经成功提交的数据,此时T2事务又对数据进行了修改,导致T1正在读取的数据发生了变化。
基于脏读已经解决的场景再次举例,如李四正在看张三已经提交的代码,而张三觉得代码不够好,又重新修改了某个字段并进行了提交,而李四发现刚刚读取的代码发生了变化,和之前读取的数据不一致。这种情况就是不可重复读。
如何解决“不可重复读”?
给李四读取代码的操作加上“限制”,也就是“写加锁”,张三和李四约定好,李四在读取代码的时候,张三不能进行修改操作。
这个“读加锁”的操作,降低了事务的并发性,降低了数据库的效率,但提高了隔离性,提高了数据的准确性

3.幻读(Phantom Read)

同一事务中, 用同样的操作读取两次, 得到的记录数不相同,对于两个事务T1,T2,虽然T1在A表中读取了一个字段,然后T2又在A表中插入了一些新的数据时,T1再读取该表时,就会发现神不知鬼不觉的多出几行了。
基于不可重复读的已经解决的场景进行举例,假设一张表有三个字段,李四要对这张表进行读取,这几个字段下的记录李四和张三约定修改,但此时张三虽然未读之前已经提交的值进行修改,但又往表中新增了一个字段,此时李四发现表中有四个字段,怀疑自己是不是读错了表,这就是幻读问题了。
如何解决“幻读问题”?
解决幻读问题的办法是串行化, 也就是舍弃并发或者使用间隙锁, 此时只要李四在读取内容, 张三就不能进行任何操作。

三、事务隔离的基本锁

行锁、表锁和间隙锁是实现事务隔离级别的基本锁类型。

行锁:指对表中的某一行数据进行锁定,当有事务修改该行数据时,其他事务无法同时修改该行数据,从而保证数据的一致性。行锁的粒度最细,对并发性能的影响最小。
表锁:指对整张表进行锁定,当有事务对表中任意一行数据进行修改时,其他事务无法修改整张表中的任意一行数据,从而保证数据的一致性。表锁的粒度最大,对并发性能的影响最大。
间隙锁:指对一个索引范围中的“空隙”进行锁定,防止其他事务在这个范围内插入新数据。间隙锁用于解决幻读问题,例如在某个事务中执行了一个范围查询,然后在范围内的间隙处插入了新数据,这时再次执行相同的查询,会发现有一些行出现了两次,这就是幻读。通过间隙锁,可以防止其他事务插入新的数据,从而避免幻读。

四、不可重复读和幻读的区别

1.发生场景不同:不可重复读主要涉及到修改数据,而幻读则主要涉及到插入或删除数据。 不可重复读指的是在同一个事务中,多次读取同一行数据,但是每次读取的结果都不同,这是因为在这个事务读取数据的期间,其他事务修改了这些数据所导致的;幻读指的是在同一个事务中,多次执行相同的查询,但是每次查询返回的行数却不同,这是因为在这个事务读取数据的期间,其他事务插入了新的数据所导致的
2.解决方案不同:不可重复读的解决方案通常是使用行锁或者表锁来解决,而幻读的解决方案通常是使用间隙锁来解决。

五、MySQL事务的四个隔离级别

MySQL中有 4 种事务隔离级别, 由低到高依次为 读未提交 (Read Uncommitted), 读已提交 (Read Committed) , 可重复读 (Repeatable Read) , 串行化(Serializable)
这些隔离级别与问题的对应关系如下:

事物隔离级别脏读不可重复读幻读
读未提交(READ UNCOMMITTED)
读已提交 (Read Committed)×
可重复读 (Repeatable Read)××
串行化(Serializable)×××

1.read uncommitted(读未提交数据):不做任何限制, 事务之间都是随意并发执行的,并发程度最高,隔离性最差.允许事务读取未被其他事务提交的变更。(脏读、不可重复读和幻读的问题都会出现)
2. read committed(读已提交数据):对写操作加锁, 并发程度降低, 隔离性提高,只允许事务读取已经被其他事务提交的变更。(可以避免脏读,但不可重复读和幻读的问题仍然可能出现)
3.repeatable read(可重复读):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新(update)。(可以避免脏读和不可重复读,但幻读仍然存在)
4. serializable(串行化):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新和删除操作,所有并发问题都可避免,但性能十分低下(因为你不完成就都不可以弄,效率太低)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值