• 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. 一致性

    在这里插入图片描述

  • 相关阅读:
    keepalived双机热备超详细入门介绍
    STL源码阅读小记(六)——Any
    bugku-web-XXX二手车交易市场
    小学期-中期总结报告
    springboot校园安全通事件报告小程序-计算机毕业设计源码02445
    echarts的bug,在series里写tooltip,不起作用,要在全局先写tooltip:{}才起作用,如果在series里写的不起作用就写到全局里
    vulhub redis-4-unacc
    redis笔记【面试】
    Linux|centos7下部署安装alertmanager并实现邮箱和微信告警
    欠拟合、过拟合现象,及解决办法
  • 原文地址:https://blog.csdn.net/qq_52154068/article/details/133522623