MySQL——事务ACID&隔离级别
数据库事务ACID&隔离级别
什么是事务
事务是用户定义的一个数据库操作序列。这些操作要么全执行,要么全不执行,是一个不可分割的工作单元。在关系型数据库中,事务可以是一条SQL语句,也可以是一组SQL语句或整个程序。
程序和事务是两个概念。一般地将,一个程序包含多个事务。
事务的开始和结束可以由用户显示控制。如果用户未显示定义事务,则有数据库管理系统按默认规定划分事务。在SQL中,定义事务的语句:
begin/start transaction
commit
rollback
事务通常以begin/start transaction开始,以commit或rollback结束。
- begin/start transaction 表示启动一个事务
- commit 表示提交,即提交事务的所有操作,将事务中所有对数据库的增删改写回到磁盘上的物理数据库中去,事务正常结束;
- rollback表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续执行,将事务中所有对数据库已完成的增删改操作全部撤销,回滚到事务开始时的状态;
事务的ACID特性
事务具有四个特性:原子性(Atomicity)、一致性(Consistency)、隔离型(Isolation)、持久性(Durability),简称ACID。
- 原子性 事务是数据库的逻辑工作单位,事务中的操作不可拆分,要么全做,要么全不做;
- 一致性 事务的执行的结果必须使数据库从一个一致性状态变到另一个一致性状态;
- 隔离性 一个事务的执行不能被其它事务干扰,即一个事务的内部操作及使用的数据库对其他并发事务是隔离的,并发执行的各个事务之间互不干扰;
- 持久性 持久性也称永久性,一个事物一旦提交,它对数据库中的数据的改变就是永久性的,接下来的其他操作或故障不应该对其执行结果有任何影响;
举一个经典的银行转账例子:账户A余额1500元,账户B余额2000元,账户A需要想账户B转账1000;简单来说需要2步操作:第1步,账户A余额1500-1000=500;第2步账户B余额2000+1000=3000;原子性:这两步要么全做,要么全部做;不能账户A余额减少1000而账户B的余额没有相应的增加1000,保证这2个操作是一个原子操作。一致性:事务(转账)开始时账户A的余额1500,账户B余额2000,一共3500;事务(转账)结束时账户A余额500,账户B余额3000,一共3500;从一个一致性状态来到另一个一致性状态并且保证账户余额不为负数(可见一致性与原子性密切相关)。隔离性:在转账的构成中,事务没有提交(转账没有结束),查询账户A、B的余额均不会变化;如果此时账户C给账户B转账500,那么当两个事务(转账)都结束的时候,B账户余额应该是A转给B的1000加上C转给B的500再加开始的余额2000。持久性:一旦转账成功(事务提交),两个账户的里面的余额就会真的发生变化(会把数据写入数据库做持久化保存)。
在DBMS中,保证了一个操作的序列全部执行或全部不执行(原子性),从一个一致性状态变到另一个一致性状态(一致性),操作一旦提交就持久化到数据库中(持久性),当多个事务同时操作同一个数据之间互不干扰(隔离性);当多个事务并发操作事,如果控制不好隔离级别,就有可能产生脏读、不可重复读或者幻读问题。
隔离级别
隔离级别要比想象的要复杂,四种隔离级别,每一种隔离级别规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离可以执行更高并发,系统开销也更低。
不同的RDMS厂商的默认隔离级别不一样,Oracle、Sql Server为已提交读(Read committed),MySQL为可重复读(Repeatable read)。
| 隔离级别 | 脏读(Dirty Read)可能性 | 不可重复读(NonRepeatable Read)可能性 | 幻读(Phantom Read)可能性 |
|---|---|---|---|
| 未提交读(Read uncommitted) | 可能 | 可能 | 可能 |
| 已提交读(Read committed) | 不可能 | 可能 | 可能 |
| 可重复读(Repeatable read) | 不可能 | 不可能 | 可能 |
| 可串行化(Serializable) | 不可能 | 不可能 | 不可能 |
脏读:事务T1读取了另一个事务T2未提交的insert、update、delete的数据,因为事务T2没有提交事务T1读取到的数据为脏数据,称为脏读。
不可重复读:事务T1多次读取同一数据期间,另一个事务T2对此数据进行update、delete操作;T1多次读取的数据不一致,称为不可重复读。
幻读:一个事务T1通过检索条件,读取N条数据,另一个事务T2写入了1条满足T1检索条件的数据,后续T1对检索的数据进行修改时,发现影响的数据记录数N+1,称为幻读。
未提交读(Read uncommitted)
-- 创建表tx
create table tx (id int auto_increment,name varchar(10),primary key(id)) engine=innodb;
-- 查看全局事务隔离级别
select @@global.tx_isolation;
-- 查看会话事务隔离级别
select @@session.tx_isolation;
-- 设置会话事务隔离级别
set session transaction isolation level read uncommitted
set session transaction isolation level read committed
set session transaction isolation level repeatable read
set session transaction isolation level serializable
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 会话2设置隔离级别 | set session transaction isolation level read uncommitted; | |
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 开启事务 | begin; | begin; |
| 查看数据 | select * from tx; ![]() |
select * from tx; ![]() |
| 会话1写入数据 | insert into tx (name) values ('a'); ![]() |
|
| 查看数据 | select * from tx; ![]() |
select * from tx; ![]() |
| 会话1事务回滚 | rollback; | |
| 会话2查看数据 | select * from tx; ![]() |
|
| 会话2事务提交 | commit; |
将会话2的事务隔离级别设置为未提交读,会话2中的事务能够读取会话1事务中未提交的数据,产生脏读;
未提交读最低的隔离级别,允许读取并发事务尚未提交的数据,会出现脏读、不可重复读、幻读
已提交读(Read committed)
-- 写入数据
insert into tx (name) values ('a');
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 会话2设置隔离级别 | set session transaction isolation level read committed; | |
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 开启事务 | begin; | begin; |
| 查看数据 | select * from tx where id=2; ![]() |
select * from tx where id=2; ![]() |
| 会话1更新数据 | update tx set name='b' where id=2; ![]() |
|
| 查看数据 | select * from tx where id=2; ![]() |
select * from tx where id=2; ![]() |
| 会话1事务提交 | commit; | |
| 会话2查看数据 | select * from tx where id=2; ![]() |
|
| 会话2事务提交 | commit; |
将会话2的事务隔离级别设置为已提交读:会话2事务未能读取会话1事务未提交的数据,解决了脏读问题;当会话1事务提交后,会话1再次读取数据,读取到会话1事务修改的数据,产生了不可重复读的问题
已提交读允许读取并发事务尚已提交的数据,解决脏读问题,仍会出现不可重复读、幻读。
可重复读(Repeatable read)
-- 写入数据
insert into tx (name) values ('aa');
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 会话2设置隔离级别 | set session transaction isolation level repeatable read; | |
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 开启事务 | begin; | begin; |
| 查看数据 | select * from tx where id >1; ![]() |
select * from tx where id >1; ![]() |
| 会话1更新数据 | update tx set name='c' where id=2; ![]() |
|
| 查看数据 | select * from tx where id >1; ![]() |
select * from tx where id >1; ![]() |
| 会话1事务写入数据 | insert into tx (name) values ('aaa'); ![]() |
|
| 查看数据 | select * from tx where id >1; ![]() |
select * from tx where id >1; ![]() |
| 会话1事务提交 | commit; | |
| 会话2查看数据 | select * from tx where id>1; ![]() |
|
| 会话2查看数据 | select * from tx where id>2; ![]() |
|
| 会话2更新数据 | update tx set name='bb' where id>3; ![]() |
|
| 会话2事务提交 | commit; | |
| 查看数据 | select * from tx where id >1; ![]() |
select * from tx where id >1; ![]() |
将会话2的事务隔离级别设置为可重复读:会话2事务未能读取到会话1事务修改的id=2的数据,当会话1事务提交后,会话2事务再次读取仍未读取到会话1事务修改id=2的数据,解决了不可重复读的问题;但会话1事务读取id>2的数据为1条,更新id>2的数据Rows matched: 2 Changed: 2,影响2条数据产生幻读问题,可通过锁机制Next-Key Lock解决。
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 查看数据 | select * from tx where id=2; ![]() |
select * from tx where id=2; ![]() |
| 开启事务 | begin; | begin; |
| 查看数据 | select * from tx where id=2; ![]() |
|
| 会话1更新数据 | update tx set name='d' where id=2; ![]() |
|
| 查看数据 | select * from tx where id=2; ![]() |
|
| 会话1事务提交 | commit; | |
| 会话2查看数据 | select * from tx where id=2; ![]() |
|
| 会话2事务提交 | commit; |
注意这个场景:会话2事务隔离级别依然是可重复读,会话2事务读取到会话1事务提交的数据,是不是很困惑?
可重复读解决的是不可重复读问题,此场景没有产生不可重复读问题(第一次select);属于一致性非锁定读/快照读,通过MVCC机制实现。
- MySQL的读有一致性非锁定度/一致性锁定读
- 一致性非锁定度(俗称快照读),普通的SELECT,通过多版本并发控制(MVCC)实现。
- 一致性锁定读(俗称当前读),SELECT...FOR UPDATE/SELECT...LOCK IN SHARE MODE。
可串行化(Serializable)
此隔离级别很简单,读操作加共享锁,写操作加排他锁,读写互斥。使用悲观锁的理论,实现简单,避免了脏读、不可重复读、幻读,并发能力降低。
| session1 | session2 | |
|---|---|---|
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 会话2设置隔离级别 | set session transaction isolation level serializable; | |
| 查看事务隔离级别 | select @@session.tx_isolation; ![]() |
select @@session.tx_isolation; ![]() |
| 会话2开启事务 | begin; | |
| 会话2查看数据 | select * from tx where id=2; ![]() |
|
| 会话1查看数据 | select * from tx where id=2; ![]() |
|
| 会话1查看数据 | select * from tx where id=2 lock in share mode; ![]() |
|
| 会话1查看数据 | select * from tx where id=2 for update; ![]() |
|
| 会话2修改数据 | update tx set name='e' where id=2; ![]() |
|
| 会话1查看数据 | select * from tx where id=2; ![]() |
|
| 会话1查看数据 | select * from tx where id=2 lock in share mode; ![]() |
上面通过命令行演示了MySQL中不同的事务隔离级别,以及不同的事务隔离级别解决的问题;在实际工作中需根据业务场景设置相应的事务隔离级别。
MySQL——事务ACID&隔离级别的更多相关文章
- MySQL事务及隔离级别详解
MySQL事务及隔离级别详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL的基本架构 MySQL的基本架构可以分为三块,即连接池,核心功能层,存储引擎层. 1> ...
- MySQL事务学习-->隔离级别
MySQL事务学习-->隔离级别 6 事务的隔离级别 设置的目的 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别. 数据库是要被广大客户所共享访问的,那么在数据库操作过程中 ...
- MySql事务的隔离级别及作用
逻辑工作单元遵循一系列(ACID)规则则称为事务. 原子性:保证事务是一系列的运作,如果中间过程有一个不成功则全部回滚,全部成功则成功.保证了事务的原则性. 一致性:一致性指的是比如A向B转100块钱 ...
- MySQL事务及隔离级别(读书小结)
标签: MySQL事务 隔离 0.什么是事务? 事务是指MySQL的一些操作看做是一个不可分割的执行单元.事务的特点是要么所有操作都执行成功,要么一个都不执行.也就是如果一个事务有操作执行失败,那么就 ...
- mysql 事务、隔离级别
一.事务的四大特性(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有 ...
- 数据库事务ACID/隔离级别
参考博客 1. 事务的定义 事务是用户定义的一个数据库操作序列.这些操作要么全执行,要么全不执行,是一个不可分割的工作单元.在关系型数据库中,事务可以是一条SQL语句,也可以是一组SQL语句或整个程序 ...
- mysql事务、隔离级别
一.事务简介 事务是一组操作的集合,它是一一个不可分割的工作单位,事务会把所有的操作作为- -个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败. 二.有关事务操作 mysql中 ...
- MySql事务及隔离级别
在数据库中,所谓事务是指作为单个逻辑工作单元执行的一系列操作. 事务的操作: 先定义开始一个事务,然后对数据作修改操作, 这时如果提交(COMMIT),这些修改就永久地保存下来 如果回退(ROLLBA ...
- [转]MySQL事务学习-->隔离级别
From : http://blog.csdn.net/mchdba/article/details/12837427 6 事务的隔离级别 设置的目的 在数据库操作中,为了有效保证并发读取数据的正确性 ...
随机推荐
- 处理textarea里Enter(回车换行符)
Enter换行符 如果包含有回车换行符,在字符串中表现为"\n": 会返回一条字符串: 原文章:https://blog.csdn.net/shenlf_bk/article/de ...
- AJAX接口-拉购网职位搜索爬虫
拉购网职位搜索爬虫 分析职位搜索调用接口: 浏览器开发者模式(快捷键F12)切换手机模式,打开拉购网职位搜索链接 https://m.lagou.com/search.html 输入搜索关键词, 例如 ...
- 5分钟GET我使用Github 5 年总结的这些骚操作!
我使用 Github 已经有 5 年多了,今天毫无保留地把自己觉得比较有用的 Gihub 小技巧送给关注 JavaGuide 的各位小伙伴. 这篇文章肝了很久,就挺用心的,大家看内容就知道了. 如果觉 ...
- python爬虫00什么是爬虫
用一个自动化的程序把网站背后的程序爬取下来. 在互联网上许许多多的网站,他们都是托管在服务器上的,这些服务器24小时运行着,刻刻 等待着别人的请求.所以,爬虫首先会模拟请求,就好像你在浏览器输入网址, ...
- Uipath_考证学习之路
写在前面 第一次考证的时候,就是为了考证而考证,从网上获取了试题,修改了一下,就通过了,对 REFramework的了解甚少,经过几周的学习,决定赶在 4.30号考证收费之前再重新考一次. 原文章发表 ...
- [MIT6.006] 16. Dijkstra
先回顾下上节课的内容: 下面来看一个定理:对于所有的点来说,放松操作总是满足 d[v] ≥ δ(s, v).即点s到点v的最短路径总是小于或等于当前点d的路径权重.证明如下: 在正是进入复杂的图前,先 ...
- binary hacks读数笔记(nm命令)
nm命令(names):输出包含三个部分:1 符号值.默认显示十六进制,也可以指定: 2 符号类型.小写表示是本地符号,大写表示全局符号(external); 3 符号名称. 例如:nm Simple ...
- kubernetes存储类与PV与PVC关系及实践
StorageClass & PV & PVC关系图 Volumes是最基础的存储抽象,其支持多种类型,包括本地存储.NFS.FC以及众多的云存储,我们也可以编写自己的存储插件来支持特 ...
- Abbott的复仇(Abbott's Revenge)
题目:有一个最多包含9*9个交叉点的迷宫.输入起点.离开起点时的朝向和终点,求一条最短路(多解时任意输出一个即可). 这个迷宫的特殊之处在于:进入一个交叉点的方向(用NEWS这4个字母分别表示北东西南 ...
- 这 5 个开源的能挣钱的 SpringBoot 项目,真TMD香!
不得不佩服 Spring Boot 的生态如此强大,今天我给大家推荐几款 Gitee 上优秀的后台开源版本的管理系统,小伙伴们再也不用从头到尾撸一个项目了,简直就是接私活,挣钱的利器啊. SmartA ...
























