MySQL事务管理

在这里插入图片描述

1. 什么是事务

举个例子:
比如说,我们需要让张三转钱给李四,那么在数据库里面就有3步,第一步就是在数据库中找到张三这个人的钱,第二步就是在张三数据库中减去,第三步在李四数据库中加上。

那么如果在第二步突然断电了,张三钱减去了,但是李四的钱没有加上,那么该怎么办呢?所以mysql中引入了事务这个概念。把这3步做完或者是一个或者多个sql语句的集合,叫做事务。

事务本不是数据库类软件天然有的,事务本质工作其实是为了简化程序员的工作模型

备注:我们后面把 MySQL 中的一行信息,称为一行记录。

事务就是一组DML语句组成,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部失败,是一个整体。MySQL提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。
在这里插入图片描述
不过mysqld要提供事务的机制,就注定了mysqld内部编码和数据结构的支持。因为mysqld一定会同时存在多个事务,所以mysqld要对多个事务以某种数据结构和算法管理起来

所有,一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性
在这里插入图片描述
在这里插入图片描述
上面四个属性,可以简称为 ACID 。
原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation,又称独立性)
持久性(Durability)。

1.1 事务的版本支持

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持。
查看数据库引擎:
在这里插入图片描述
这里的transactions的意思就是事务。

1.2 事务提交方式

事务的提交方式常见的有两种:自动提交和手动提交。
查看事务提交方式:
在这里插入图片描述
这个意思是mysql的事务是会自动被提交的。

用 SET 来改变 MySQL 的自动提交模式:
在这里插入图片描述
SET AUTOCOMMIT=0 禁止自动提交,SET AUTOCOMMIT=1 开启自动提交。

2. 事务常见操作方式

为了便于演示,我们将mysql的默认隔离级别设置成读未提交。具体操作我们后面专门会讲,现在已使用为主。
在这里插入图片描述
需要重启终端,进行查看。
在这里插入图片描述
下面我们要用两个客户端来进行操作,首先,创建一个简单的银行测试表:
在这里插入图片描述
正常演示 - 证明事务的开始与回滚:
在这里插入图片描述
查看事务是否自动提交。我们故意设置成自动提交,看看该选项是否影响begin。
在这里插入图片描述
开始一个事务。
在这里插入图片描述
创建一个保存点save1。
在这里插入图片描述
插入一条记录后,我们再创建一个保存点save2。
在这里插入图片描述
然后我们再插入一条数据,发现两条记录都在。

下面我们回滚到保存点save2:
在这里插入图片描述
此时我们在保存点2后插入的数据就没有了。
在这里插入图片描述
直接rollback,回滚在最开始。

非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)
在这里插入图片描述
当前表内无数据,并且依旧是自动提交。
在这里插入图片描述
begin也是开启事务的一种方式。数据已经存在,但没有commit。我们直接ctrl + \ 异常终止MySQL。
在这里插入图片描述
终端A崩溃了。
在这里插入图片描述
我们在终端B查看数据自动回滚到最开始的地方。

非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
在这里插入图片描述
commit就是提交事务。
在这里插入图片描述
在终端B可以看到数据存在了,所以commit的作用是将数据持久。

非正常演示3 - 对比试验。证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响
在这里插入图片描述
我们把事务提交方式设置成关闭。
在这里插入图片描述
终端A崩溃后,我们查看终端B的。
在这里插入图片描述
所以,autocommit是否自动提交,并不影响用户手动对事务的操作

非正常演示4 - 证明单条 SQL 与事务的关系
加粗样式
我们这里关闭自动提交,然后再插入一条数据。
在这里插入图片描述
崩溃前插入是有的。我们再查看终端B。
在这里插入图片描述
可以看到我们的王五没了,这里我们也没有启动事务,自动提交也是关闭的。
在这里插入图片描述
这是我们之前一直写的单SQL,我们再查看一下终端B。
在这里插入图片描述
王五存在数据库中。

结论:单SQL默认是以事务的方式进行提交的,只不过你的事务只有一个SQL语句

autocommit 是否自动提交,并不影响用户手动开启事务。它影响的是:如果我们没有手动开启事务,就默认我们的SQL就是一个事务,SQL执行完毕会按照autocommit 来决定是否提交
在这里插入图片描述
事务操作注意事项:
在这里插入图片描述

3. 事务隔离级别

如何理解隔离性
MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行。
一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题,可以随时回滚。所以单个事务,对用户表现出来的特性,就是原子性。

毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。

数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性。
数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别。

隔离级别:
在这里插入图片描述

3.1 查看与设置隔离性

在这里插入图片描述
查看全局隔级别。
在这里插入图片描述
这两个是查看会话(当前)全局隔级别。

设置当前会话 or 全局隔离级别语法
在这里插入图片描述

3.2 读未提交

前面我们做的例子都是读未提交的。
事务中,所谓的提交commit,是不是把数据刷盘了呢
不是,刷盘的过程是mysqld自己会执行的。commit设置事务的状态,表示该数据已经算是交付给mysqld。

几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用
在这里插入图片描述
此时的置隔离级别为 读未提交。
在这里插入图片描述
我们在终端A更新了数据,但是没有进行提交。
在这里插入图片描述
但是我们在终端B读到终端A更新但是未commit的数据。

一个事务在执行中,读到另一个执行中事务的更新(或其它操作)但是未commit的数据,这种现象叫做脏读(dirty read)

3.3 读提交

只有你提交了,才能被其它读到。
在这里插入图片描述
我们设置读提交,然后需要重新启动。
在这里插入图片描述
现在的设置就是读提交了。
在这里插入图片描述
两边同时开启事务,并且终端A进行更改,但是没有commit。
在这里插入图片描述
终端A的发生了变化,终端B的没有发生变化。
在这里插入图片描述
提交了之后,两边都发生了变化。但是我们的终端B还在事务中。并未commit,那么就造成了,同一个事务内,同样的读取,在不同的时间段
(依旧还在事务操作中!),读取到了不同的值,这种现象叫做不可重复读。

这个是问题吗?
很多人认为这是正常的,因为没有提交的时候看不到,提交了才能看到。但是这确实是一个问题。

举个例子:
比如说在公司发年终奖,工资在[2000,3000]给个ipad,工资在[4000,5000]给个华为手机。那么假设张三的工资在3000,那么在事务筛选的时候,张三是ipad,但是此时公司的老板看张三今年表现不错,给张三的工资涨了1000,那么张三的工资就来到了4000,那么在筛选[4000,5000]时又有了张三,说明给张飞发了2个礼物。那么就存在着问题。

3.4 可重复读

在这里插入图片描述
我们进行设置可重复读。
在这里插入图片描述
然后两边同时开启事务:
在这里插入图片描述
然后我们进行操作数据:
在这里插入图片描述
终端B看不到修改的数据,那么我们试试提交。
在这里插入图片描述
还是看不到。

可以看到,在终端B中,事务无论什么时候进行查找,看到的结果都是一致的,这叫做可重复读
在这里插入图片描述
我们在终端B进行提交commit后,再次查看数据,数据就更新了。

我们的mysql采用的就是这个方式,其它数据库在可重复读情况的时候,无法屏蔽其它事务insert的数据(为什么?因为隔离性实现是对数据加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题),会造成虽然大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读(phantom read)。很明显,MySQL在RR级别的时候,是解决了幻读问题的(解决的方式是用Next-Key锁(GAP+行锁)解决的。

3.5 串行化

对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用
在这里插入图片描述
在这里插入图片描述
我们在这里先启动的是终端A,后启动的是终端B。两个读取不会串行化,共享锁。
在这里插入图片描述
终端A中有更新或者其它操作,会阻塞。直到终端B事务提交。
在这里插入图片描述
超出时间会有报错。
在这里插入图片描述
此时终端B还看不到事务A的修改。
在这里插入图片描述
当终端A结束后才能看见。
在这里插入图片描述
在这里插入图片描述

4. 一致性

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值