[MySQL数据库之事务、读现象、数据库锁机制、多版本控制MVCC、事务隔离机制]
[MySQL数据库之事务、读现象、数据库锁机制、多版本控制MVCC、事务隔离机制]
事务
1、什么是事务:
事务(Transaction),顾名思义就是要做的或所做的事情,数据库事务指的则是作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部执行,要么全部不执行。
2、为什么需要事务
把一系列sql放入一个事务中有两个目的:
1、为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2、当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
当一个事务被提交给了DBMS(数据库管理系统),则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态(要么全执行,要么全都不执行);同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。
但在现实情况下,失败的风险很高。在一个数据库事务的执行过程中,有可能会遇上事务操作失败、数据库系统/操作系统失败,甚至是存储介质失败等情况。这便需要DBMS对一个执行失败的事务执行恢复操作,将其数据库状态恢复到一致状态(数据的一致性得到保证的状态)。为了实现将数据库状态恢复到一致状态的功能,DBMS通常需要维护事务日志以追踪事务中所有影响数据库数据的操作。
3、事务的4个特性
这四个特性通常称为ACID特性
1、原子性(Atomicity)
一个事务的执行是整体性的,不可分割,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
2、一致性(Consistency)
事务应确保数据库的状态从一个一致状态转变为另一个一致状态。例如转账行为中:一个人减了50元,另
外一个人就应该加上这50元,而不能是40元。其他一致状态的含义是数据库中的数据应满足完整性约束,
例如字段约束不能为负数,事务执行完毕后的该字段也同样不是负数
3、隔离性(Isolation)
多个事务并发执行时,一个事务的执行不应影响其他事务的执行,
且多个事务不能看到对方的中间状态(提交或者回滚之前的状态)
4、持久性(Durability)
一个事务的提交,对数据库的修改是永久保存在数据库中的,不受外部因素或其他操作影响。
验证事务的一致性、隔离性
4、事务的3种运行模式
隐式 == 自动
显式 == 手动
自动提交事务(隐式开启、隐式提交)
每一条单独的SQL语句都在其执行完成后进行自动提交事务,即执行 SQL 语句后就会马上自动隐式执行 COMMIT 操作。如果出现错误,则进行事务回滚至之前状态。
显式事务(显式开启、显式提交)
通过指定事务开始语句来显式开启事务来作为开始,并由以提交命令或者回滚命令来提交或者回滚事务作为结束的一段代码就是一个用户定义的显式事务。SQL SERVER、MYSQL和ORACLE都以不同的方式来开始显式事务
1)SQL SERVER:以begin transaction开启事务开始,由commit transaction 提交事务或者rollback transaction 回滚事务结束。
2)MySQL: 以start transaction或者begin;开启事务commit提交事务或者rollback回滚事务,commit或者rollback事务都结束
# 注意
这种方式在当你使用commit或者rollback后,事务就结束了
再次进入事务状态需要再次start transaction或begin
3)ORACLE:ORACLE事务起始于第一条SQL语句的执行,不需要特别指定事务的开始和结束,一个事务结束就意味着下一事务开始。以commit或不带有savepoint子句的rollback命令作为结束。
隐式事务(隐式开启、显式提交)
在隐式事务中,无需使用BEGIN TRANASACTION 来开启事务,每个SQL语句第一次执行就会开启一个事务,直到用COMMIT [TRANSACTION]来提交或者ROLLBACK [TRANSACTION]来回滚结束事务。
1)SQL SERVER中使用下面语句来开启和关闭隐式事务模式。或者通过 Sql Server Managerment Studio,在 Tools -> Options Query Execution -> SQL Server -> ANSI 选项中勾选SET IMPLICIT_TRANSACTIONS设置开启还是关闭隐式事务模式。
ser implicit_autocommit on -- on是开启,off是关闭
2)ORACLE默认就是隐式开启事务,显式提交事务。可以通过下面语句开启自动提交事务,以达到隐式提交事务。
set autocommit on; -- on是开启自动事务模式,off是关闭自动提交事务模式
3)MYSQL通过关闭自动提交事务,来达到隐式开启事务,显式提交事务的目的。
set session autocommit = 0; -- 0是关闭,1是开启;session是设置当前会话变量,global是设置全局变量
总结:MySQL 默认为每条sql开启事务,并且会在本条sql执行完毕后自动执行commit提交,若想设置手动提交,有两种方式
方式一:直接用 SET 来改变 MySQL 的自动提交模式(下述设置均为会话级别的设置):
- set autocommit=0 禁止自动提交
- set autocommit=1 开启自动提交
方式二: 手动开启的事务里默认不会自动提交
# 手动开启的事务里默认不会自动提交,所以我们可以将要执行的sql语句放在我们自己手动开启的事务里
start transaction; 或者begin; 开启事务
commit; 提交事务
rollback;回滚事务
commit或者rollback事务都结束
start transaction;
update user set name="EGON" where id =1;
commit;
# 注意
这种方式在当你使用commit或者rollback后,事务就结束了
再次进入事务状态需要再次start transaction
数据库读现象
数据库管理软件的“读现象”指的是当多个事务并发执行时,在读取数据方面可能碰到的问题,包括有脏读、不可重复读和幻读。
ps:对于一些数据库管理软件会自带相应的机制去解决脏读、不可重复读、幻读等问题,因为这些自带的机制,下述的一些实验现象可能在某一数据库管理软件的默认机制下并不成立,即我们并不能在所有数据库管理软件中看到所有的读现象。所以此处我们暂且抛开具体的某个数据库管理软件的默认机制的干扰,暂时假设没有附加任何机制为前提,单纯地去理解数据库的读现象。
脏读 (dirty read)
事务T2更新了一行记录的内容,但是并没有提交所做的修改。
事务T1读取更新后的行,然后T1执行回滚操作,取消了刚才所做的修改。此时T1所读取的行就无效了,称之为脏数据。
不可重复读取 (non repeatable read)
事务T1读取一行记录,紧接着事务T2修改了T1刚才读取的那一行记录并且提交了。
然后T1又再次读取这行记录,发现与刚才读取的结果不同。这就称为“不可重复”读,因为T1原来读取的那行记录已经发生了变化。
幻像读取 (phantom read)
幻读(phantom read)”是不可重复读(Non-repeatable reads)的一种特殊场景:
当事务没有获取范围锁的情况下执行SELECT … WHERE操作有可能会发生“幻影读(phantom read)”。
事务T1读取或修改了指定的WHERE子句所返回的结果集。
然后事务T2新插入一行记录,这行记录恰好可以满足T1所使用的查询条件中的WHERE 子句的条件。
然后T1又使用相同的查询再次对表进行检索,但是此时却看到了事务T2刚才插入的新行或者发现了处于WHRE子句范围内,但却未曾修改过的记录。就好像“幻觉”一样,因为对T1来说这一行就像突然出现的一样。
一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读。
数据库锁机制:行级锁之共享锁与排他锁
行级锁分为共享锁和排他锁两种
与行处理相关的sql有:insert、update、delete、select,这四类sql在操作记录行时,可以为行加上锁,但需要知道的是
1、对于insert、update、delete语句,InnoDB会自动给涉及的数据加锁,而且是排他锁(X);
2、对于普通的select语句,InnoDB不会加任何锁,需要我们手动自己加,可以加两种类型的锁,如下所示
# 共享锁(S):SELECT ... LOCK IN SHARE MODE; -- 查出的记录行都会被锁住
# 排他锁(X):SELECT ... FOR UPDATE; -- 查出的记录行都会被锁住
共享锁(Share Lock)
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,获准共享锁的事务只能读数据,不能修改数据直到已释放所有共享锁,所以共享锁可以支持并发读
如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁或不加锁(在其他事务里一定不能再加排他锁,但是在事务T自己里面是可以加的),反之亦然。
用法
SELECT ... LOCK IN SHARE MODE;
在查询语句后面增加LOCK IN SHARE MODE
,Mysql会对查询结果中的每行都加共享锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞。其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据。
排他锁(eXclusive Lock)
排他锁又称为写锁,简称X锁,顾名思义,排他锁就是不能与其他所并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再对该行加任何类型的其他他锁(共享锁和排他锁),但是获取排他锁的事务是可以对数据就行读取和修改。
用法
SELECT ... FOR UPDATE;
在查询语句后面增加FOR UPDATE
,Mysql会对查询结果中的每行都加排他锁,当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞。
特例:加过排他锁的数据行在其他事务种是不能修改数据的,也不能通过for update和lock in share mode锁的方式查询数据,但可以直接通过select ...from...查询数据,因为普通select查询没有任何锁机制。
数据库锁机制
1、一旦事务1对数据A加了排它锁
那么其他事务无法对数据A加任何锁
只有事务1可以操作数据A,而且可以读也可以写
2、一旦事务1对数据A加了共享锁
那么其他事务可以对数据A加锁,但只能加共享锁
一旦多个事务都会数据A加了共享锁,大家都只能读不能改
多版本控制MVCC:Snapshot Read vs Current Read
MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control) (注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control)。MVCC最大的好处,相信也是耳熟能详:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,这也是为什么现阶段,几乎所有的RDBMS,都支持了MVCC。
在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
在一个支持MVCC并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以MySQL InnoDB为例:
快照读:简单的select操作,属于快照读,不加锁。(当然,也有例外,下面会分析)
select * from table where ?;
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加 S锁 (共享锁)外,其他的操作,都加的是 X锁 (排它锁)。
为什么将 插入/更新/删除 操作,都归为当前读?可以看看下面这个 更新 操作,在数据库中的执行流程:
从图中,可以看到,一个Update操作的具体流程。当Update SQL被发给MySQL后,MySQL Server会根据where条件,读取第一条满足条件的记录,然后InnoDB引擎会将第一条记录返回,并加锁 (current read)。待MySQL Server收到这条加锁的记录之后,会再发起一个Update请求,更新这条记录。一条记录操作完成,再读取下一条记录,直至没有满足条件的记录为止。因此,Update操作内部,就包含了一个当前读。同理,Delete操作也一样。Insert操作会稍微有些不同,简单来说,就是Insert操作可能会触发Unique Key的冲突检查,也会进行一个当前读。
注:根据上图的交互,针对一条当前读的SQL语句,InnoDB与MySQL Server的交互,是一条一条进行的,因此,加锁也是一条一条进行的。先对一条满足条件的记录加锁,返回给MySQL Server,做一些DML操作;然后在读取下一条加锁,直至读取完毕。
事务隔离机制
事务具有原子性、一致性、隔离性、持久性四大特性,而隔离性顾名思义指的就是事务彼此之间隔离开,多个事务在同时处理一个数据时彼此之间互相不影响,如如果隔离的不够好就有可能会产生脏读、不可重复度、幻读等读现象,为此,隔离性总共分为四种级别
由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。
需要强调的是:我们确实可以采用提高事务的隔离级别的方式来解决脏读、不可重复读、幻读等问题,但与此同时,事务的隔离级别越
高,并发能力也就越低。所以,还需要读者根据业务需要进行权衡。
MySQL/InnoDB定义的4种隔离级别:(mysql的级别不是ios定义的级别,iso定义的RR存在幻读)
未提交读(Read Uncommited)
未提交读是最低的隔离级别。通过名字我们就可以知道,在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据。
提交读(Read committed)
提交读也可以翻译成读已提交,通过名字也可以分析出,在一个事务修改数据过程中,如果事务还没提交,其他事务不能读该数据。
提交读这种隔离级别保证了读到的任何数据都是提交的数据,避免了脏读(dirty reads)。但是不保证事务重新读的时候能读到相同的数据,因为在每次数据读完之后其他事务可以修改刚才读到的数据。存在幻读现象。
可重复读(Repeatable read)
可重复读隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。
可序列化(Serializable)
从MVCC并发控制退化为基于锁的并发控制。不区别快照读与当前读,所有的读操作均为当前读,读加读锁 (S锁),写加写锁 (X锁)。
Serializable隔离级别下,读写冲突,因此并发度急剧下降,在MySQL/InnoDB下不建议使用。
在MYSQL的事务引擎中,INNODB是使用范围最广的。它默认的事务隔离级别是REPEATABLE READ(可重复读),在标准的事务隔离级别定义下,REPEATABLE READ是不能防止幻读产生的。INNODB使用了next-key locks实现了防止幻读的发生。
数据库事务详解参考:https://www.cnblogs.com/linhaifeng/articles/14387841.html
数据库锁机制详解参考:https://www.cnblogs.com/linhaifeng/articles/14386584.html
事务隔离机制详解参考:https://www.cnblogs.com/linhaifeng/articles/14387903.html
多版本控制MVCC详情参考:https://www.cnblogs.com/crazylqy/p/7611069.html
[MySQL数据库之事务、读现象、数据库锁机制、多版本控制MVCC、事务隔离机制]的更多相关文章
- Mysql事务及行级锁的理解
在最近的开发中,碰到一个需求签到,每个用户每天只能签到一次,那么怎么去判断某个用户当天是否签到呢?因为当属表设计的时候,每个用户签到一次,即向表中插入一条记录,根据记录的数量和时间来判断用户当天是否签 ...
- MySQL从删库到跑路_高级(七)——事务和锁
作者:天山老妖S 链接:http://blog.51cto.com/9291927 一.事务简介 1.事务简介 事务(Transaction)是指作为单个逻辑工作单元执行的一系列操作. 2.事物的特效 ...
- Mysql事务及行级锁
事务隔离级别 数据库事务隔离级别,只是针对一个事务能不能读取其它事务的中间结果. Read Uncommitted (读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离 ...
- MySQL数据库的隔离级别之可重复读为什么能够有效防止幻读现象的出现
可重复读隔离级别,不允许存在幻读,该隔离级别之所以能够有效防止幻读现象的出现,是因为可重复读这个隔离级别有用到GAP锁(间隙锁).下面我们以解析SQL语句为切入点,来解释个中原因. 前提条件:①数据库 ...
- MySQL数据库_索引_事务_优化 _锁_存储引擎_存储过程_CAP
##一.基础 ## * 插入 INSERT INTO table_name ( field1, field2,...fieldN ) ...
- Mysql数据库的数据类型、索引、锁、事务和视图
Mysql数据库的数据类型.索引.锁.事务和视图 数据的类型 1)数据类型: 数据长什么样? 数据需要多少空间来存放? 系统内置数据类型和用户定义数据类型 2)MySql 支持多种列类型: 数值类型 ...
- MySQL数据库~~~~~锁和事务
一 锁 innodb存储引擎默认是行级锁 行级锁定最大的特点就是锁定对象的颗粒度很小,也是目前各大数据库管理软件所实现的锁定颗粒度最小的.由于锁定颗粒度很小,所以发生锁定资源争用的概率也最小,能够给予 ...
- MySQL数据库InnoDB存储引擎中的锁机制
MySQL数据库InnoDB存储引擎中的锁机制 http://www.uml.org.cn/sjjm/201205302.asp 00 – 基本概念 当并发事务同时访问一个资源的时候,有可能 ...
- Spring事务管理与数据库隔离级别的关系(Spring+mysql)
之前写过一篇文章<数据库隔离级别(mysql+Spring)与性能分析 >,里面很多问题写的不是很专业,也不是很有逻辑性,现在重新整理一下,希望对大家有帮助. 这部分通过两天时间反复的 ...
随机推荐
- 攻防世界 reverse 进阶 1-4
1.dmd-50 suctf-2016 md5后比较,在线解md5得到: md5(md5($pass)),所以将grape再进行MD5 b781cbb29054db12f88f08c6e161c199 ...
- Java之常用API
API概述 什么是API API (Application Programming Interface) :应用程序编程接口 java中的API 指的就是 JDK 中提供的各种功能的 Java类,这些 ...
- 【Azure Developer】Github Action部署资源(ARM模板)到Azure中国区时,遇见登录问题的解决办法
问题描述 在参考文档"使用 GitHub Actions 部署 ARM 模板"一文中,由于是在中国区Azure上操作,所以生产的部署凭证为中国区凭证.当创建工作流时,在登录到Azu ...
- [Azure Devops] 使用 Azure Pipelines 实现 CI
1. 什么是 Azure Pipelines Azure Pipelines 会自动构建和测试代码项目,以将其提供给其他人.它适用于任何语言或项目类型.Azure Pipelines 结合了持续集成 ...
- shell分支与循环结构
1. 条件选择 1.1 条件判断分支介绍 格式 if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMM ...
- Dynamics CRM字段安全配置文件
在实施Dynamics CRM的过程中,有些需求会提到部分字段针对特殊的人员或者团队进行显示.更新以及创建的需求的控制.这里我们就需要用到字段安全性文件这个功能.此功能针对具体实体的字段进行配置可以达 ...
- Spring Cloud Gateway 扩展支持动态限流
之前分享过 一篇 <Spring Cloud Gateway 原生的接口限流该怎么玩>, 核心是依赖Spring Cloud Gateway 默认提供的限流过滤器来实现 原生Request ...
- Python 高级进阶知识(一)
参考 Python学习手册 第四版 1 from vs import import 模块 : 导入的一整个模块(python中模块对应一个py文件) 因为import使用一个变量名引用整个模块对象,所 ...
- JVM学习笔记(二):JVM基本结构
1 来源 来源:<Java虚拟机 JVM故障诊断与性能优化>--葛一鸣 章节:第二章 本文是第二章的一些笔记整理. 2 JVM基本参数-Xmx java命令的一般形式如下: java [- ...
- day11.迭代器与生成器
一.迭代器 1.迭代器即用来迭代取值的工具,而迭代是重复反馈过程的活动,其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次"迭代",而每一次迭代得到的结果会作为下一次 ...