详解mysql事务(事务,隔离级别,死锁,mvcc)

概念

事务是访问并更新数据库中数据项的一个程序执行单元。在事务中的操作,要么都执行修改,要么都不执行

转账的例子:比如说A要向B转账1000元,那将涉及两个过程:A的余额减少,B的余额增加,如果在A减少之后系统崩溃,导致B没有增加,这样就丢数据了,所以事务就是要保证这个过程的正确性

ACID特性

A(automicity),原子性。指的是整个数据库事务是不可分隔的工作单位,只有使事务中所有的数据库操作都执行成功,整个事务的执行才算成功,事务中任务一个sql语句执行失败,那么已经执行成功的sql语句也必须撤销,数据库状态应该退回到执行事务前的状态。 要么都做,要么都不做。

C(consistency),一致性。指事务将数据库从一种状态变为另一种一致的状态。因此,事务是一致性的单位,如果事务中某个动作失败了,系统可以自动地撤销事务使其返回初始化的状态。例如转账中,前后的总额应该是保持一致的

I(isolation),隔离性/并发控制/可串行化/锁。并发访问数据库时,一个事务所作的修改在最终提交以前,对其他事务是不可见的。 一个用户的事务不能被其他事务所干扰,即各个并发事务之间数据库是独立的

D(durability),持久性。事务一旦提交,其结果是永久性的,即使发生宕机等故障,数据库也能将数据恢复

事务存在的并发问题

  1. 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据都是脏数据
  2. 不可重复读(两次读取的数据不一致):事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。侧重于修改
  3. 幻读:一个事务A读取了一些数据,事务B又插入了新数据,在随后的查询中,A发现了一些原本不存在的数据,就想发生了幻觉一样 。侧重于新增或删除

所以为了解决并发问题,引入了隔离级别

事务的隔离级别

  • read unCommitted:未提交读。事务A的更新操作还未提交,但是事务B就能读取到事务A更新后的数据
  • read committed:读已提交。一个事务从开始直到提交之前,所作的任何修改对其他事务都是不可见的
  • repeatable read:可重复读。mysql的默认隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行(Innodb的默认隔离级别)
  • serializable:可串行化。在读取的每一行数据上都加锁。

隔离级别

脏读

不可重复读

幻读

read uncommited

read commited

没有

repeatable-read

没有(因为事务提交了才可见)

没有

串行化

没有

没有

没有

事务的死锁

概念:当两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象

例如:

start transaction;
update stock_price set close = 45 where stock_id = 4 and date = '2021-03-05';
update stock_price set close = 46 where stock_id = 6 and date = '2021-03-06';
commit;
start transaction;
update stock_price set close = 46 where stock_id = 6 and date = '2021-03-06';
update stock_price set close = 45 where stock_id = 4 and date = '2021-03-05';
commit;

如果事务A和B都同时执行了第一条update语句,同时也锁定了该行数据,接着去执行第二条语句,都在尝试锁定第二条数据,都在等待对方释放锁,同时又都持有对方的锁,则陷入了死循环。

解决::

  1. 将持有最少排他锁的事务进行回滚(InnoDB目前的处理方法)
  2. 设定超时时间,当到达超时时间后放弃请求
  3. 数据库实现了死锁检测机制

MVCC

概念:并发多版本控制 Multi-Version Concurrency Control,指在使用 read commited(已提交读),repeatable read(可重复读)这两种隔离级别的事务在执行普通的select操作时访问记录的版本链的过程,可以使不同事务的读-写,写-读操作并发执行,从而提升系统性能

read committed和repeatable read隔离级别的最大区别就是它们生成Read View 的时机不同,在read commited中是每次查询都会生成一个实时的read view ,做到保证每次提交后的数据是处于当前的可见状态。而repeatable read中,在当前事务第一次查询时生成当前的readView,并且一直沿用到该事务提交,以此来保证可重复读的一致性

原理:

InnoDB的mvcc是通过在每行记录后面保存两个隐藏的列来实现的,分别是行的创建时间,行的过期时间(并不是真正的时间,而是系统版本号),而事务开始时刻的系统版本号会作为事务的版本号。查找时值查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样就可以确保事务读取的行,要么是事务开始前已经存在的,要么是事务资深插入或修改过的

幻读

前提条件:InnoDb中,可重复读隔离级别,使用当前读
表现:一个事务在前后两个查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行(新插入的行),只在当前读的情况下会出现
(可重复读的隔离级别:可重复读指的是相同的查询条件出来的字段值是相同的,并不包含新插入的数据,所以还是存在幻读的问题)
影响:
会造成一个事务中先产生的锁,无法锁住后加入的满足条件的行
产生数据一致性问题,在一个事务中,先对符合条件的没有表行做变更,而在事务提交前有新的符合目标的行加入,这样通过binlog恢复数据时会将所有符合条件的目标行都进行变更的
产生的原因:行锁只能锁住行,即使把所有的行记录都上锁,也阻止不了新插入的记录
解决:

  1. MVCC + 可重复读的隔离级别 可以防止幻读,也就是 使用快照读是没有幻读的
  2. next-key lock :记录锁(行锁),间隙锁。行锁是加在索引上的锁,间隙锁是加在索引之间的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值