mysql 主键冲突 多个事务回滚_Mysql事务

事务定义

一个事务会涉及大量的cpu操作和IO操作,这些操作会被打包成一个执行单元,要么同时完成,要么同时都不完成。

事务是一组原子性的sql命令或者说是一个独立的工作单元,如果其中任何一条sql语句因为崩溃或者其他原因执行失败,那么该组所有的sql语句都不会执行。如果没有显示启动事务,数据库会根据autocommit的值,默认每条sql操作都会自动提交。

事务的特性ACID

原子性(A)

一个事务中的所有操作,要么都完成,要么都不执行,对于一个事务来说,不可能只执行其中的一部分。

一致性(C)

数据库总是从一个一致性的状态转换到另一个一致性的状态

隔离性(I)

一个事务所做的修改在最终提交之前,对其他事务是不可见的。多个事务之间的操作相互不影响。每降低一个事务的隔离级别都能提高数据库的并发,但同时不安全性就增加了。关于事务的隔离级别后续还要详细讨论。这里简单介绍一下:

读未提交:其他事务未提交就可以读。

读已提交:其他事务只有提交了才能读。

可重复读:只管自己启动事务时候的状态,不接受其他事务的影响。

串行化:按照顺序提交事务保证了数据的安全性,但无法实现并发。

持久性(D)

事务一旦提交,就要更新到数据库中,不能回滚。就算服务器宕机,仍然需要在下次启动的时候自动执行事务中的sql命令,体现到数据库中。

数据库事务隔离界别

介绍

隔离界别

脏读

不可重复读

幻读

未提交读(Read uncommited)

可能

可能

可能

已提交读(Read commited)

不可能

可能

可能

可重复读(Repeatable read)

不可能

不可能

可能

串行化(Serializable)

不可能

不可能

不可能

未提交读(Read uncommited):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。

已提交读(Read commited):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别。

可重复读(Repeatable read):可重复读。在同一事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,改级别消除了不可重复读,但还是存在幻象读,但InnoDB解决了幻读。

串行化:完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

准备数据

准备一个账户表,表里三个字段,分别是主键id,账户名和金额

验证RU(未提交读)

1、开启两个会话,设置隔离级别为read uncommited

530d9ed0b5e2a6ad5f50a9932730a3d5.png

2、会话1开启事务

0bb21e18fa6c891ec6f97e383a87129f.png3、会话2开启事务并插入一条数据

6bcdda6e29059971564025ef18c86fe9.png4、会话1开始查询数据库,查到了会话2事务未提交的数据

229711df91a48788bbb6e431652e4784.png5、会话2如果此时回滚了,会话1就查不到了

3bfacdcf54c1d9839aa94d7188a7d4ca.png

3c98052cbe5390e470792f405cadc3cc.png小结:在RU模式下,一个事务可以读取到另一个未提交事务的数据,导致了脏读。如果另一个事务回滚了,就会造成数据的不一致性。RU是事务隔离级别中最低的。

RC(读提交)

1、将会话1和会话2的隔离级别设置成读提交模式

3688917779de665befdb419665f2c52c.png2、会话1和会话2都开启事务,会话1查询当前数据

5ca834d9b7faeb4e894e398fca59c0e0.png

3b3b4082bab23bd9661dd323f8aa592f.png3、会话2更新数据但未提交,会话1查询当前数据还是没改

c5b6a819a3c017b586f72aebcf2bf7df.png

a04e1633b018d79279f3e49a2a414edb.png4、但是会话2此时事务提交,会话1查询当前数据变了

cd8c19fdff482997831f5254df270b1c.png

c0f7a70ab4eeed3e78f7da634e7b9901.png

小结:在RC模式下,我们发现,当另一个事务没有提交数据修改时,当前事务时读不到修改后的数据的,这就避免了读未提交模式的脏读。但有一个问题,在当前事务中,两次select的数据不一样,这就存在了不可重复读的问题。PS:RC隔离级别是Oracle数据库默认的隔离级别。

RR(可重复读)

1、将会话1和会话2的隔离级别都设置成可重复读

7ee055b613418cc3566f4ed697d6aed4.png2、会话1开启事务并查询当前数据,会话2开启事务并更新数据

93380985148b65693ada9d2ccb0628d6.png

86967c02da648963e981405d6a62811f.png3、此时会话1查询数据还是之前的数据

5c181f90c73b76e3bcfb079a5c632b8d.png4、然后会话2提交事务,会话1查询数据还是之前的数据,这表示会话2的更改并没有影响当前的事务,可以重复读取。

c7d82c6996cebc6df35ab03f5905e878.png

f57ad4d22c0aafc340cecb2e26cc00d8.png5、此时会话1提交当前事务,并再次读取数据,发现其他事务改了数据

8f1a6a1627a0b737b4a734b25ac9bc92.png小结:在RR模式下,我们解决了不可重复读的问题,即在这种隔离级别下,一个事务中我们能够保证获取一样的数据(即使有其他事务正在改当前的数据行)。但是无法避免幻读, 幻读简单的解释就是在数据有新增的时候,也无法保证两次得到的数据不一致但是不同数据库对不同的RR级别有不同的实现,有时候加上间隙锁来避免幻读。

InnoDB解决了幻读

结论

首先说结论:在RR的隔离级别下,InnoDB使用MVCC和next-key locks(间隙锁)解决幻读。MVCC解决的是普通读(快照读)的幻读,间隙锁解决的是当前读情况下的幻读。

幻读是什么

(首先声明:在RR模式下,引擎是InnoDB,无法产生以下效果。)

1、事务1先执行,但未提交

结果为:OK row xx表名成功影响多少行 2、事务2后执行,并且提交

3、事务1再select一下,结果集为:

··· 李云龙,10000

这时,事务1蒙了,不是已经将id>10的所有人的金额都更新成1000了吗,怎么多出一个人金额是10000?这是已提交事务2对事务1产生的影响,这个影响就叫做幻读。

幻读和不可重复读的区别

不可重复读:多次读取一条记录,发现该记录中某些列值被修改过。

幻读:只要是说多次读取一个范围内的记录(包括直接查询所有记录结果或者做聚合统计),发现结果不一致(一般指的是记录增多,记录的减少应该也算是幻读)。

怎么解决幻读

当前读

所谓当前读,指的是加锁的select(S锁或者X锁),update或者delete语句。在RR的事务隔离级别下,数据库会使用间隙锁来锁住本条记录以及索引区间。例如:

select * from account where id>10 for update;锁住的就是id=10的记录以及id>10的这个区间范围,避免范围间插入记录,以避免产生幻影行记录。

普通读

因为普通读是不会加锁的读,所以解决幻读的手段是MVCC。MVCC会给每行元祖加一些辅助字段,记录创建版本号和删除版本号。在每一个事务启动的时候,都有一个唯一的递增的版本号。每开启一个新事务,事务的版本号就会递增。MYSQL默认的隔离级别(可重复读Repeatable Read)下,增删改查就变成下面这样:

select:读取创建版本小于或等于当前事务版本号,并且删除版本为空或大于当前事务版本号的记录。这样可以保证在读取之前记录是存在的。

insert:将当前事务的版本号保存至行的创建版本号。

update:新插入一行,并以当前事务版本号作为新行的创建版本号,同时将原纪录行的删除版本号设置为当前事务版本号。

delete:将当前事务版本号保存至行的删除版本号。 有点绕,总结下来就是每行多了两个版本号,一个创建版本号和一个删除版本号,都是保存事务的版本号。下面举个例子理解一下: 例如我插入一条记录,事务id=1,那么记录如下:

id

name

createversion

deleteversion

1

马云

1

如果我把name更新成刘强东,事务id=2,那么记录就变成

id

name

createversion

deleteversion

1

马云

1

2

2

刘强东

2

=> 可以看出,原来的元祖的deleteversion为更新的这个事务的id,并且新增一条

如果删除的话,假设事务id=3,删除id=2的记录

id

name

createversion

deleteversion

1

马云

1

2

2

刘强东

2

3

关键点来了,如果我现在读取的话,需要同时满足两个条件:

1、读取创建版本小于或等于当前事务的版本号,这意味着数据在这个事务之前被创建

2、删除版本为空或者大于当前事务版本号的记录。这意味着删除操作在这个事务之后发生

所以当事务1插入一条记录,事物2更新这条记录并删除这条记录之后,事务1再次查询这条记录,只有id=1的记录满足这两个条件,所以结果为:(避免了幻读)

id

name

createversion

deleteversion

1

马云

1

2

串行化

所有事务串行执行,是最高的隔离级别,性能最差

总结

这篇文章就到这了,总的来说数据库事务的四个特性ACID和四种隔离级别(RU,RC,RR,串行化)以及会产生的问题(脏读、不可重复读、幻读)是面试的高频问点,什么东西都需要积累,然后反复的温习,这样才能记忆和理解的更深刻。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值