MySQL事务管理

MySQL事务管理_第1张图片

文章目录

  • 1. 什么是事务
    • 1.1 事务的版本支持
    • 1.2 事务提交方式
  • 2. 事务常见操作方式
  • 3. 事务隔离级别
    • 3.1 查看与设置隔离性
    • 3.2 读未提交
    • 3.3 读提交
    • 3.4 可重复读
    • 3.5 串行化
  • 4. 一致性

1. 什么是事务

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

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

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

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

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

所有,一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性
MySQL事务管理_第3张图片
MySQL事务管理_第4张图片
上面四个属性,可以简称为 ACID 。
原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation,又称独立性)
持久性(Durability)。

1.1 事务的版本支持

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持。
查看数据库引擎:
MySQL事务管理_第5张图片
这里的transactions的意思就是事务。

1.2 事务提交方式

事务的提交方式常见的有两种:自动提交和手动提交。
查看事务提交方式:
MySQL事务管理_第6张图片
这个意思是mysql的事务是会自动被提交的。

用 SET 来改变 MySQL 的自动提交模式:
MySQL事务管理_第7张图片
SET AUTOCOMMIT=0 禁止自动提交,SET AUTOCOMMIT=1 开启自动提交。

2. 事务常见操作方式

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

下面我们回滚到保存点save2:
MySQL事务管理_第16张图片
此时我们在保存点2后插入的数据就没有了。
MySQL事务管理_第17张图片
直接rollback,回滚在最开始。

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

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

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

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

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

autocommit 是否自动提交,并不影响用户手动开启事务。它影响的是:如果我们没有手动开启事务,就默认我们的SQL就是一个事务,SQL执行完毕会按照autocommit 来决定是否提交
MySQL事务管理_第31张图片
事务操作注意事项:
MySQL事务管理_第32张图片

3. 事务隔离级别

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

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

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

隔离级别:
MySQL事务管理_第33张图片

3.1 查看与设置隔离性

MySQL事务管理_第34张图片
查看全局隔级别。
MySQL事务管理_第35张图片
这两个是查看会话(当前)全局隔级别。

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

3.2 读未提交

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

几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用
MySQL事务管理_第36张图片
此时的置隔离级别为 读未提交。
MySQL事务管理_第37张图片
我们在终端A更新了数据,但是没有进行提交。
MySQL事务管理_第38张图片
但是我们在终端B读到终端A更新但是未commit的数据。

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

3.3 读提交

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

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

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

3.4 可重复读

MySQL事务管理_第44张图片
我们进行设置可重复读。
MySQL事务管理_第45张图片
然后两边同时开启事务:
MySQL事务管理_第46张图片
然后我们进行操作数据:
MySQL事务管理_第47张图片
终端B看不到修改的数据,那么我们试试提交。
MySQL事务管理_第48张图片
还是看不到。

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

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

3.5 串行化

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

4. 一致性

MySQL事务管理_第57张图片

你可能感兴趣的:(MySql,mysql,数据库,事务)