1. 什么是事务

事务

事务是一个整体,由一条或者多条SQL语句组成,这些SQL语句要么都执行成功,要么都执行失败,

只要有一条SQL出现异常,整个操作就会回滚,整个业务执行失败

比如: 银行的转账业务,张三给李四转账500元 , 至少要操作两次数据库, 张三 -500, 李四 + 500,这中间任何一步出现问题,整个操作就必须全部回滚, 这样才能保证用户和银行都没有损失

回滚

即在事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部撤销,滚回到事务开始时的状态

比如:张三转账完成后,卧槽,发现转多了,叫李四退回来,最终张三和李四的钱还是保持原样,这个就是回滚

MYSQL 中可以有两种方式进行事务的操作:

  • 自动提交事务
  • 手动提交事务

自动提交事务

MySQL 默认每一条 DML(增删改)语句都是一个单独的事务,每条语句都会自动开启一个事务,语句执行完毕自动提交事务,MySQL默认是自动提交事务

手动提交事务

开启事务 start transaction; 或者 BEGIN;
提交事务 commit;
回滚事务 rollback;

  • 执行成功的情况: 开启事务 -> 执行多条 SQL 语句 -> 成功提交事务
  • 执行失败的情况: 开启事务 -> 执行多条 SQL 语句 -> 事务的回滚

如何取消自动提交
MySQL默认是自动提交事务,如有需要,可设置为手动提交。设置步骤如下:
1) 登录mysql,查看autocommit状态。
       SHOW VARIABLES LIKE 'autocommit';

on :自动提交
off : 手动提交
2) 把 autocommit 改成 off;
     SET @@autocommit=off;

这样,以后执行修改操作前就需要开启事务,执行sql完成,必须提交后才能生效

2. 事务的四大特性(ACID)

原子性(Atomic)

事务是一个不可分割的整体,事务中所有的sql语句要么全部执行成功,要么全部失败

比如:张三转账给李四500,需要执行两条sql,张三账户 -500,李四账户+500

update account set money = money - 500 where name = '张三';
update account set money = money + 500 where name = '李四';

这两个sql必须全部成功,才能算是真正的转账成功,这就是事务的原子性,不可拆分。

一致性(Consistency)

事务在执行前数据库的状态与执行后数据库的状态保持一致

比如:转账前2个人的总金额是 2000,中间不管怎么转账,转几次账,转账后2个人总金额也是2000。这就是事务的一致性。

隔离性(Isolation)

一个事务的执行不能被其他事务干扰。
即一个事务内部的操作及使用的数据,对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
这个与事务设置的隔离级别有密切的关系

比如:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

持久性(Durability)

一旦事务执行成功,对数据库的修改是持久的。就算关机,数据也是要保存下来的

比如:我成功修改了数据库的一条数据后,突然停电了,那条数据依然在数据库中,永久的保存着。

3. 事务的隔离级别

数据库的隔离级别有4种,级别从低到高为:
读未提交(read uncommitted)、读已提交(read committed)、可重复读(repeatable read)、串行化(serializable)

谈到事务的隔离级别,首先就得来了解一下事务并发访问产生的问题:脏读、不可重复读、幻读
这几个问题和数据库隔离级别密切相关,如果不设置合理的隔离级别,那么就可能出现这三个并发问题

脏读:

一个事务读取到了另一个事务中尚未提交的数据

举个栗子:
如果当前的数据库隔离级别为最低——读未提交(read uncommitted)
假定当前有两个事务在并发执行,分别是:事务A、事务B

事务A: 张三向李四转账500元
对应SQL命令如下(在同一个事务):

update account set money = money - 500 where name = '张三';
update account set money = money + 500 where name = '李四';

事务B:李四查询账户余额
对应SQL命令如下:

SELECT money FROM account where name = '李四';

当张三给李四转账后(事务A执行,但是事务未提交),
李四此时正好去查询账户(事务B执行),发现账户增加了500(此时即发生了脏读),非常高兴。
但是,突然张三突然反悔了,于是迅速回滚了事务。
现在李四的账户变成了初始的状态,但是李四读取出来的金额,却多了500。

李四啊,别人都还没提交呢,你就去读取了,别人万一回滚咋办,所以你读的是脏数据,这叫脏读,是有问题的!

如何解决脏读问题?

脏读非常危险的,比如张三向李四购买商品,张三开启事务,向李四账号转入 500 块,然后打电话给李四说钱 已经转了。李四一查询钱到账了,发货给张三。张三收到货后回滚事务,李四的再查看钱没了。

解决方案:
将全局的隔离级别进行提升为: 读已提交(read committed)
--  设置事务隔离级别为 read committed
set global transaction isolation level read committed;

重新开启DOS窗口, 查看设置是否成功:
-- 查看事务隔离级别
select @@tx_isolation;

设置完成后,再次重新执行转账操作(事务A),不提交,然后李四执行查询操作(事务B),
内心毫无波澜,因为账户金额还是最初的样子,说明现在没有脏读问题了。

大多数数据库的默认级别就是read committed,比如Sql Server , Oracle

但是,这种隔离级别还不够呢,还可能存在不可重复读的问题。

不可重复读:

同一个事务中,进行查询操作,但是每次读取的数据内容是不一样的,
这是由于在查询间隔中,数据被另一个事务修改并提交了

举个栗子:
如果当前的数据库隔离级别为 读已提交(read uncommitted)
假定当前有两个事务在并发执行,还是事务A、事务B

事务A: 张三向李四转账500元
对应SQL命令如下(在同一个事务):

update account set money = money - 500 where name = '张三';
update account set money = money + 500 where name = '李四';

事务B:李四查询账户余额
对应SQL命令如下:

SELECT money FROM account where name = '李四';

李四着急忙慌的,先去查询一次自己的账户余额(事务B),嗯,有1000,不错。
当张三给李四转账成功后(事务A执行并提交),
李四老婆叫他再次确认下自己的余额,于是李四又去查询一次自己的账户余额(事务B),我嚓,怎么和之前查询不一样哦,多了500。
我这还处于同一个事务中呢,这读取结果却不一样,到底哪次是对的?
这就是所谓的不可重复读问题。

下面这张图很好的诠释了这个执行过程:

如何解决不可重复读问题?

我们可以考虑这样一种实际情况:
比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客 户,结果在一个事务中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作人员就不知道以哪个为准了

解决方案:
将全局的隔离级别进行提升为:可重复读(repeatable read) 
-- 设置事务隔离级别为 repeatable read 
set global transaction isolation level repeatable read;

重新开启DOS窗口, 查看设置是否成功:
-- 查看事务隔离级别
select @@tx_isolation;

设置完成后,恢复数据,再次重复上述操作,然后可以发现,李四两次查询的金额是相同的,说明已经没有不可重复读问题了。

mysql 数据库的默认级别就是repeatable read

但是,这样就万事大吉了吗,no,还可能存在幻读问题。

幻读:

在同一个事务中,前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
这是由于事务在执行期间,另一个事务新增了数据并提交了

举个栗子:
假定当前有两个事务在并发执行,还是事务C、事务D

事务C: 先查询有没有id为3的记录,如果没有,则进行插入
对应SQL命令如下(在同一个事务):

select * from account where id = 3;
INSERT INTO account VALUES(3,'王五',1000);

事务D:插入一条新记录
对应SQL命令如下:

INSERT INTO account VALUES(3,'王五',1000);

执行顺序为:
  1)事务C执行第一条SQL, 查询是否有id为3的记录
        结果发现,没有,那我可以插入了。
  2)事务D新增一条记录,并提交
  3)事务C执行第二条SQL,新增id为3的记录,发现报错——主键重复
       见鬼了,我刚才读到的结果应该可以支持我这样操作才对啊,为什么现在不可以

select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。

如何解决幻读问题?

我们可以考虑这样一种实际情况:
比如银行程序需要将查询结果分别输出到电脑屏幕和发短信给客 户,结果在一个事务中针对不同的输出目的地进行的两次查询不一致,导致文件和屏幕中的结果不一致,银行工作 人员就不知道以哪个为准了

解决方案:
将事务隔离级别设置到最高:串行化(serializable)

如果一个事务,使用了SERIALIZABLE——可串行化隔离级别时,在这个事务没有被提交之前 , 
其他的线程,只能等到当前操作完成之后,才能进行操作,这样会非常耗时,
而且,影响数据库的性能,数据库不会使用这种隔离级别

-- 设置事务隔离级别为 serializable
set global transaction isolation level serializable;

重新开启DOS窗口, 查看设置是否成功:
-- 查看事务隔离级别
select @@tx_isolation;

设置完成后,恢复数据,再次重复上述操作

执行顺序为:
   1)事务C执行第一条SQL, 查询是否有id为3的记录
        结果发现,没有,那我可以插入了。
   2)事务D插入一条记录,这个操作无法完成,光标一直闪烁
   3)事务C执行第二条SQL,新增id为3的记录, 提交事务 数据插入成功.
   4)事务D在事务C提交之后, 再执行,但是主键冲突出现错误

这就解决了幻读问题

tips:
serializable 串行化可以彻底解决幻读,但是事务只能排队执行,严重影响效率,数据库不会使用这种隔离级别

并发问题区分

不可重复读和脏读的区别:脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
幻读和不可重复读的区别:都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读针对的是另外事务的update操作,而幻读针对的是另外事务的insert操作。

总结

  • 脏读说的是事务知道了自己本不应该知道的东西,强调的动作是查询,我看到了自己不该看的东西 ;

  • 不可重复读强调的是一个人查的时候,其他人却可以增删改, 等我再查的时候,和之前查询的不一致,也就是我两次看到了不一样的东西;

  • 幻读说的是我看到了数据是这么多,其他人又插了一条新的,等我拿刚才的查询结果再执行操作的时候,冷不丁发现又多了一条数据

MySQ如何解决幻读问题?

既然不设置串行化,MySQL到底怎么解决幻读问题?

先说结论,MySQL 存储引擎 InnoDB 在可重复读(repeatable read)隔离级别下是解决了幻读问题的。
方法:
是通过next-key lock在当前读事务开启时,

  1. 给涉及到的行加写锁(行锁)防止写操作;
  2. 给涉及到的行两端加 间隙锁(Gap Lock) 防止新增行写入;从而解决了幻读问题。

顾名思义,行锁就是锁住行的锁,
间隙锁,锁的就是两个值之间的空隙。比如一个表,初始化插入了 7 个记录,这就产生了 8 个间隙。

由于ID大于7,被间隙锁(7,+∞)锁住。这样就确保了无法再插入新的记录。

MySQL将行锁 + 间隙锁组合统称为 next-key lock,通过 next-key lock 解决了幻读问题。

注意
next-key lock的确是解决了幻读问题,但是next-key lock在并发情况下也经常会造成死锁。死锁检测和处理也会花费时间,一定程度上影响到并发量.

数据库事务的四大特性和隔离级别,一文带你看通透相关推荐

  1. 数据库事务的四大特性以及隔离级别

    本篇文章主要介绍数据库事务的四大特性ACID,以及数据库的隔离级别. 事务 概念 事务指的是满足 ACID 特性的一系列操作.在数据库中,可以通过 Commit提交一个事务,也可以使用 Rollbac ...

  2. 数据库事务的四大特性和隔离级别

    数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么全部执行,要么全部都不执行. 一个逻辑工作单元要成为事务,必须满足事务的四大特性(ACID).即 ...

  3. mysql 四大基础操作_事务的四大特性和隔离级别

    MySQL是开源免费和功能多面的小型数据库,MySQL也是目前流行通用的关系型数据库,已经被 Oracle 收购了.随着版本更新升级,加入一些高级功能,MySQL6.x 版本也开始收费.不过本教程将使 ...

  4. 数据库ACID四大特性到底为了啥,一文带你看通透

    小伙伴想精准查找自己想看的MySQL文章?喏 → MySQL江湖路 | 专栏目录   说起数据库四大特性,同学们张口就来,ACID!那为什么要ACID?每种特性的原理又是什么?如何实现的?废话少说,哈 ...

  5. mysql特性举例_MySQL事务的四大特性和隔离级别

    1.事务的四大特性(ACID) #### 1.1.原子性(Atomicity) 原子性是指事务包含的一系列操作要么全部成功,要么全部回滚,不存在部分成功或者部分回滚,是一个不可分割的操作整体. 1.2 ...

  6. 事务的四大特性和隔离级别

    1.事务的四大特性(ACID):指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durabilit ...

  7. mysql四种隔离级别知乎_详解MySQL事务的四大特性和隔离级别

    1.事务的四大特性(ACID) 1.1.原子性(Atomicity) 原子性是指事务包含的一系列操作要么全部成功,要么全部回滚,不存在部分成功或者部分回滚,是一个不可分割的操作整体. 1.2.一致性( ...

  8. mysql 默认事务隔离级别_详解MySQL事务的四大特性和隔离级别

    1.事务的四大特性(ACID) 1.1.原子性(Atomicity) 原子性是指事务包含的一系列操作要么全部成功,要么全部回滚,不存在部分成功或者部分回滚,是一个不可分割的操作整体. 1.2.一致性( ...

  9. 数据库事务的四大特性和四个隔离级别

    一.数据库事务的四大特性 事物是指作为一个单元的一组有序的数据库操作,单元是不可分割的,如果一组数据的所有操作都执行成功,事物完成,进行事物提交(commit),其修改作用于所有数据库进程.有一个操作 ...

  10. 事务四大特性及隔离级别

    事务四大特性及隔离级别 咱们都知道事务有四大特性ACID,也就原子性(atomicity|ætəˈmɪsəti|). 一致性(consistency).隔离性(isolation|aɪsəˈleɪʃn ...

最新文章

  1. jieba.lcut方法
  2. 欧拉回路【洛谷习题】无序字母对
  3. [FF-A]-02-Concepts
  4. PS菜鸟入门 -- 添加滤镜
  5. codeforces 1038a(找最长的前k个字母出现相同次数的字符串)水题
  6. mysql profiles清空_MYSQL 使用show profiles 分析性能
  7. HDU 5145 - NPY and girls
  8. python学习1(下载、安装)
  9. 【Landsat 8】介绍
  10. PowerDesigner注意事项
  11. 从零开始配置vim(22)——lsp简介与treesitter 配置
  12. 操作系统——四种进程调度算法模拟实现(C语言)
  13. 软件测评师考试大纲2018
  14. cisco fabricpath 功能介绍
  15. 某品牌电批单机知识总结
  16. 唯品会等被纳入MSCI指数,中概股迎来春天
  17. 【opencv-python】寻找矩形框
  18. 京东用户行为数据分析报告(python)
  19. Java绘制椭圆和矩形(实现自由变化大小的功能)
  20. Pytorch深度学习(一):前馈神经网络(FNN)

热门文章

  1. ClassLoder总结
  2. Windows 10开启Teredo隧道连接IPV6
  3. EV:ePWM+eCAP
  4. Mask OBB 论文学习笔记
  5. safari打开图片链接显示问题
  6. 代码重构(一)原理和规范
  7. 实验二 贪吃蛇游戏的开发
  8. 【转】为什么360这种软件存活至今?程序员:打不死的小强,春风吹又生
  9. 霍纳法则c语言算法代码,霍纳法则(Horner Rule)介绍及C语言实现
  10. 百家讲坛-《老子智慧与现代爱情婚姻》