MySQL 事务

参考:我以为我对Mysql事务很熟,直到我遇到了阿里面试官

定义

数据库的事务是指一组sql语句组成的数据库逻辑处理单元,在这组的sql操作中,要么全部执行成功,要么全部执行失败。

事务的四大特性(ACID)

原子性(Atomicity)、一致性(Consistent)、隔离性(Isalotion)、持久性(Durable)

  • 原子性是指事务的原子性操作,对数据的修改要么全部执行成功,要么全部失败,实现事务的原子性,是基于日志的 Redo/Undo 机制。
  • 一致性是指执行事务前后的状态要一致,可以理解为数据一致性。
  • 隔离性侧重指事务之间相互隔离,不受影响,这个与事务设置的隔离级别有密切的关系。
  • 持久性则是指在一个事务提交后,这个事务的状态会被持久化到数据库中,也就是事务提交,对数据的新增、更新将会持久化到数据库中。
  • 原子性、隔离性、持久性都是为了保障一致性而存在的,一致性也是最终的目的。

原子性实现机制

基于日志的 Redo/Undo 机制,它们将所有对数据的更新操作都写到日志中。

Redo log 用来记录某数据块被修改后的值,可以用来恢复未写入 data file 的已成功事务更新的数据;Undo log 是用来记录数据更新前的值,保证数据更新失败能够回滚。

假如数据库在执行的过程中,不小心崩了,可以通过该日志的方式,回滚之前已经执行成功的操作,实现事务的一致性。

例:假如某个时刻数据库崩溃,在崩溃之前有事务A和事务B在执行,事务A已经提交,而事务B还未提交。当数据库重启进行 crash-recovery 时,就会通过 Redo log 将已经提交事务的更改写到数据文件,而还没有提交的就通过 Undo log 进行 roll back。

事务四大隔离级别

参考:解析MySQL事务隔离级别

  • 读未提交(READ UNCOMMITTED)
  • 读提交 (READ COMMITTED)
  • 可重复读 (REPEATABLE READ)
  • 串行化 (SERIALIZABLE)

不同事务隔离级别带来的问题:

  • 读未提交会读到另一个事务的未提交的数据,产生脏读问题
  • 读提交则解决了脏读的,出现了不可重复读,即在一个事务任意时刻读到的数据可能不一样,可能会受到其它事务对数据修改提交后的影响,一般是对于update的操作。
  • 可重复读解决了之前不可重复读和脏读的问题,但是由带来了幻读的问题,幻读一般是针对insert操作。

MySQL默认事务隔离级别:可重复读(Repeatable Read)

参考:MySQL 到底是怎么解决幻读的?

在快照读读情况下,mysql通过mvcc来避免幻读。
在当前读读情况下,mysql通过next-key来避免幻读。

MySQL 的锁机制

MySQL 锁分类

  • 分享锁/读锁(Shared Locks)
  • 排他锁/写锁(Exclusive Locks)
  • 间隙锁
  • 行锁(Record Locks)
  • 表锁

共享锁是针对同一份数据,多个读操作可以同时进行,简单来说即读加锁,不能写并且可并行读;排他锁针对写操作,假如当前写操作没有完成,那么它会阻断其它的写锁和读锁,即写加锁,其它读写都阻塞 。

行锁表锁,是从锁的粒度上进行划分的,行锁锁定当前数据行,锁的粒度小,加锁慢,发生锁冲突的概率小,并发度高,行锁也是MyISAM和InnoDB的区别之一,InnoDB支持行锁并且支持事务 。

而表锁则锁的粒度大,加锁快,开销小,但是锁冲突的概率大,并发度低。

间隙锁则分为两种:Gap Locks和Next-Key Locks。Gap Locks会锁住两个索引之间的区间,比如select * from User where id>3 and id<5 for update,就会在区间(3,5)之间加上Gap Locks。

Next-Key Locks是Gap Locks+Record Locks形成闭区间锁select * from User where id>=3 and id=<5 for update,就会在区间[3,5]之间加上Next-Key Locks。

什么操作会加锁?

在数据库的增、删、改、查中,只有增、删、改才会加上排它锁,而只是查询并不会加锁,只能通过在select语句后显式加lock in share mode或者for update来加共享锁或者排它锁。

事务加锁情况

读未提交是没有加任何锁的,所以对于它来说也就是没有隔离的效果,所以它的性能也是最好的。

对于串行化加的是一把大锁,读的时候加共享锁,不能写,写的时候,加的是排它锁,阻塞其它事务的写入和读取,若是其它的事务长时间不能写入就会直接报超时,所以它的性能也是最差的,对于它来就没有什么并发性可言。

对于读提交和可重复读,他们俩的实现是兼顾解决数据问题,然后又要有一定的并发行,所以在实现上锁机制会比串行化优化很多,提高并发性,所以性能也会比较好。

隔离级别和锁的关系

Innodb中的事务隔离级别和锁的关系

MySql数据库——事务隔离级别和锁关系学习

事务底层实现原理

读提交和可重复读的底层实现采用的是MVCC(多版本并发控制)。

实现MVCC时用到了一致性视图,用于支持读提交和可重复读的实现。

在InnoDB 中每一个事务都有一个自己的事务id,并且是唯一的,递增的 。

对于Mysql中的每一个数据行都有可能存在多个版本,在每次事务更新数据的时候,都会生成一个新的数据版本,并且把自己的数据id赋值给当前版本的row trx_id。

在这里插入图片描述
如图中所示,假如三个事务更新了同一行数据,那么就会有对应的三个数据版本。

实际上版本1、版本2并非实际物理存在的,而图中的U1和U2实际就是undo log,这v1和v2版本是根据当前v3和undo log计算出来的。

那对于一个快照来说,你知道它要遵循什么规则吗?

对于一个事务视图来说除了对自己更新的总是可见,另外还有三种情况:版本未提交的,都是不可见的;版本已经提交,但是是在创建视图之后提交的也是不可见的;版本已经提交,若是在创建视图之前提交的是可见的。

假如两个事务执行写操作,又怎么保证并发呢?

假如事务1和事务2都要执行update操作,事务1先update数据行的时候,先回获取行锁,锁定数据,当事务2要进行update操作的时候,也会取获取该数据行的行锁,但是已经被事务1占有,事务2只能wait。

若是事务1长时间没有释放锁,事务2就会出现超时异常 。

应用

@Transactional注解的参数意义以及注解实现事务的原理?

参考:spring的@Transactional注解详细用法

分布式事务

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值