必须懂的 MySQL 的事务与隔离级别

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

转载声明:转载请注明出处,本技术博客是本人原创文章

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 必须懂的 MySQL 的事务与隔离级别

  点击上方 **好好学java **,选择 **星标 **公众号


重磅资讯、干货,第一时间送达
今日推荐:微信支付的软件架构,牛逼!个人原创+1博客:点击前往,查看更多

出处:哈基石
链接:https://segmentfault.com/a/1190000022610363

事务的特性 ACID

  • 原子性(atomicity) 一个事务为不可分割的最小工作单元,要么全部提交成功,要么全部回滚,不可能只执行一部分,这就是事务的原子性- 一致性(consistency) 数据库从一个一致性状态切换到另一个一致性状态- 隔离性(isolation) 一个事务在提交之前,对其他事务是不可见的。- 永久性(durability) 一旦事务提交,那么所做的修改将会永久存储在数据库中

    事务的隔离级别

READ UNCOMMITED(未提交读) 脏读

事务中的修改即使没有提交,对其他事务都是可见的。会出现脏读(Dirty Read)的情况。

READ COMMITTED (提交读) 不可重复读

一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。也叫做不可重复读(nonrepeatable read),因为两次同样的查询,可能会存在不同的结果举例说明:比如事务A正在读数据库内容,而事务 B 修改了数据后提交了。此时事务A又读了一次数据库内容,这时出现两个内容不同的结果,称为不可重复读。

REPEATABLE READ(可重复读) 幻读 MySQL 默认的事务隔离级别

当某个事务在读取某个范围内的记录时,另外一个事务在这个范围内插入了新的记录,当之前的事务再次读取这个范围内的数据时,会产生幻行(Phantom Row)称为幻读举例说明:比如事务 A 正在读数据库内容,而事务 B 插入一条到数据库后提交了。此时事务 A 又读了一次数据库内容,这时数据库现了多一条数据称为幻读

SERIALIZABLE (可串行化)最高的隔离级别

在读取的每一行数据都上锁。导致导量的超时和等待锁的问题。

|隔离级别|脏读|不可重复度幻读加锁读
|——
|未提交读|√|√√x
|提交读|x|√√x
|可重复读|x|x√x
|可串行化|x|xx√

选择哪种模式其实是一种博弈的过程,数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。

自动提交(AUTOCOMMIT)

MySQL 默认采用自动提交(AUTOCOMMIT)模式。如果不显式地开始一个事务,则每个事务都被当做一个事务进行提交操作。MyISAM 在执行查询语句(select)前,会自动给涉及的所有表加读锁,在执行更新操作(update、delete、insert等)前,会自动给涉及的表加写锁,这个过程并不需要直接用 lock table 命令给 MyISAM 表显示加锁。MyISAM 在自动加锁的情况下,总是一次获得 sql 语句所需要的全部锁,所以显示锁表的时候,必须同时取得所有涉及表的锁,这也正是 MyISAM 表不会出现死锁(deadlock)的原因。

查看自动提交模式类型 show variables like 'autocommit'

设置自动提交模式 set autocommit = 1在事务的执行过程中,随时都可以执行锁定,锁只有 COMMIT 或 ROLLBACK 才会释放

MySQL 可以使用 SET TRANSACTION ISOLATION LEVEL 命令设置隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED

死锁

死锁是指两个或者多个事务在同一个资源上互相占用,并请求锁定对方占用的资源,从而出现恶性循环的现象。

死锁产生的原因

  1. 因为系统资源不足。1. 进程运行推进的顺序不合适。1. 资源分配不当等。
    如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则 就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。

死锁产生的条件

  1. 互斥条件:一个资源每次只能被一个进程使用。1. 占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放。1. 不可强行占有:进程已获得的资源,在末使用完之前,不能强行剥夺。1. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立。

    死锁的预防

  2. 破幻死锁产生的必要条件1. 检测到死锁的循环依赖,放弃锁的请求1. 等待锁超市,放弃锁

    乐观锁

乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于读多写少的应用场景,这样可以提高吞吐量。

乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。

乐观锁的实现方式

  1. 使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。1. 使用时间戳(timestamp)。乐观锁定的第二种实现方式和第一种差不多,同样是在需要乐观锁控制的table中增加一个字段,名称无所谓,字段类型使用时间戳(timestamp), 和上面的version类似,也是在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突。

应用场景乐观锁适用于写比较少的情况下(多读场景) ,这样可以省去了锁的开销,加大了系统的整个吞吐量。

悲观锁

悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。

应用场景一般多写的场景下用悲观锁就比较合适

最后,再附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,这是本人这几年及春招的总结,目前,已经拿到了大厂offer,拿去不谢!

下载方式

1. 首先扫描下方二维码

2. 后台回复「Java面试」即可获取

原文地址:https://sihai.blog.csdn.net/article/details/109465486

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

转载声明:转载请注明出处,本技术博客是本人原创文章

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> 必须懂的 MySQL 的事务与隔离级别


 上一篇
面试官——你知道哪几种事务失效的场景? 面试官——你知道哪几种事务失效的场景?
前言 声明式事务是Spring功能中最爽之一,可是有些时候,我们在使用声明式事务并未生效,这是为什么呢?- 今天陈某带大家来聊一聊声明事务的几种失效场景。本文将会从以下两个方面来说一下事务为什么会失效?1. @Transactional介绍
2021-04-04
下一篇 
收藏!工作中Git使用实践和常用命令流程合集 收藏!工作中Git使用实践和常用命令流程合集
工作中git是一项必不可少的技能,在项目的开发进程中起着至关重要的作用 下面介绍一些git在工作中的一些使用实践、常用流程、常用命令,供大家参考! 一:前言Git的定义是:分布式版本控制系统,用于项目开发中的版本控制。 从本质
2021-04-04