MySQL - 事务

一、(了解)定义

全称(Transaction Control Language)翻译成中文 事务控制语言,事务是访问并可能更新数据库各种数据项的一个程序执行单元,

是并发控制的单元,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,sql 能将逻辑相关的一组操作绑定在一起,以便服务器 保持数据的完整性。

二、 (了解)为什么要事务

设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:

  1. 更新客户所购商品的库存信息
  2. 保存客户付款信息--可能包括与银行系统的交互
  3. 生成订单并且保存到数据库中
  4. 更新用户相关信息,例如购物数量等等

正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。

  1. 数据库事务正是用来保证这种情况下交易的平稳性和可预测性的技术

  2. 默认情况下会自动提交,也就是说每个SQL语句都是在其完成时提交到数据库。

  3. 事务只针对DDL操作

三、(熟练掌握)事务的特性(ACID)

1、案例

A账户向B账号汇钱的例子来说明如何通过数据库事务保证数据的准确性和完整性

1、从A账号中把余额读出来(500)

2、对A账号做减法操作(500-100)

3、把结果写回A账号中(400)

4、从B账号中把余额读出来(500

5、对B账号做加法操作(500+100)

6、把结果写回B账号中(600)

2、原子性(Atomicity)

  1. 概念
    事务是数据库的逻辑工作单位,而且是必须是原子工作单位,对于其数据修改,要么全部执行,要么全部不执行。
  2. 说明
    保证1-6所有过程要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。 假如执行到第五步的时候,B账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态

3、一致性(Consistency)

  1. 概念

    指在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。也就是说数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。

    **注: **

    业务逻辑上的一致性 由开发人员进行保证。

    数据库层面 在一个事务执行之前和之后,数据会符合你设置的约束唯一约束,外键约束,check约束等)和触发器设置,并且同一个事务内部的一组操作必须全部执行成功(原子操作)

    但是,原子性并不能完全保证一致性。在多个事务并行进行的情况下,即使保证了每一个事务的原子性,仍然可能导致数据不一致的结果。为了保证并发情况下的一致性,引入了隔离性

  2. 说明

    在转账之前,A和B的账户中共有500+500=1000元钱。在转账之后,A和B的账户中共有400+600=1000元。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态。同时一致性还能保证账户余额不会变成负数等

4、隔离性(Isolation)

  1. 概念

    也称为独立性,是指并行事务的修改必须与其他并行事务的修改相互独立。一个事务处理数据,要么是其他事务执行之前的状态,要么是其他事务执行之后的状态,但不能处理其他正在处理的数据。
    企业级的数据库每一秒钟都可能应付成千上万的并发访问,因而带来了并发控制的问题。

  2. 说明

    在A向B转账的整个过程中,只要事务还没有提交(commit),查询A账户和B账户的时候,两个账户里面的钱的数量都不会有变化。
    如果在A给B转账的同时,有另外一个事务执行了C给B转账的操作,那么当两个事务都结束的时候,B账户里面的钱应该是A转给B的钱加上C转给B的钱再加上自己原有的钱

5、持久性(Durability)

  1. 概念

    一个事务一旦提交,事物的操作便永久性的保存在DB中。即使此时再执行回滚操作也不能撤消所做的更改

  2. 说明

    一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化(会把数据写入数据库做持久化保存)

四、(熟练掌握)基本操作

1、事务常用的语句

语句
BEGIN或START TRANSACTION 显式地开启一个事务;
COMMIT 也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的;
ROLLBACK 有可以使用ROLLBACK WORK,回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
SAVEPOINT identifier SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
RELEASE SAVEPOINT identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
ROLLBACK TO identifier; 把事务回滚到标记点;
SET TRANSACTION 用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。

2、MYSQL 事务处理主要有两种方法:

  1. 用 BEGIN, ROLLBACK, COMMIT来实现
    • BEGIN 开始一个事务
    • ROLLBACK 事务回滚
    • COMMIT事务提交
  2. 直接用 SET 来改变 MySQL 的自动提交模式
    • SET AUTOCOMMIT=0 | off 禁止自动提交
    • **SET AUTOCOMMIT=1 | on ** 开启自动提交

3 、案例

  1. 前期准备工作
    -- 创建银行账户表
    create table account(
        aid int primary key auto_increment comment '主键',
        card_no varchar(16) not null unique comment '银行卡号',
        name varchar(20) not null comment '姓名',
        money decimal(10,2) default 0.0 comment '金额'
    )
    -- 插入数据
    insert into account (card_no,name,money) values
    ('1', '小明', 1000),
    ('2', '娇娇', 1000);
    
  2. 第一步 开始事务
    -- 告诉系统以下所有操作,不要直接写入数据库,先存到事务日志。
    BEGIN
    
  3. 第二步 减少账户的余额
    update account set money = money - 1000 where cardno =1
    
  4. 第三步 增加账户的余额
    update account set money = money + 1000 where cardno = 2;
    
  5. 第四步 提交事务
    commit;
    
  6. 第五步 或者回滚
    rollback
    

五、(掌握)事务隔离 - 并发控制

数据库事务处理相关命令

操作命令 说明
SHOW CREATE TABLE 表名; 查看存储引擎
SET AUTOCOMMIT=0或1;或者 SET AUTOCOMMIT=off 或 on 设置是否自动提交
SELECT @@AUTOCOMMIT; 或者 show variables like '%commit%'; 查询自动提交功能状态
SELECT @@tx_isolation; 查看事务隔离级别
SET tx_isolation='READ-UNCOMMITTED'; 设置事务的隔离级别

1、并发控制

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性

2、不考虑事务的隔离性,会出现什么问题?

  1. 脏读:一个事务读取到另一个事务的未提交数据
  2. 不可重复读:两次读取的数据不一致(强调update 针对单行)
  3. 虚读(幻读):两次读取的数据不一致(强调insert或delete,范围查询)
  4. 丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖(事务A和B并发执行,A事务执行更新后,提交;B事务在A事务更新后,B事务结束前也做了对该行数据的更新操作,然后回滚,则两次更新操作都丢失了)

3、四种隔离级别

  1. Read-uncommitted:最低级别,以上情况均无法保证。(读未提交)
  2. Read-committed:可避免脏读情况发生(读已提交)
  3. Repeatable-read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读
  4. Serializable:可避免脏读、不可重复读、虚读情况的发生。(序列化,不仅有read、write锁还有range lock范围锁(没有where锁全表,有where锁where范围);对一张表的所有增删改操作必须顺序执行,性能最差)
    | 隔离级别 | 脏读 | 不可重复读 | 幻读 |
    | ---------------- | ---- | ---------- | ---- |
    | Read uncommitted | √ | √ | √ |
    | Read committed | × | √ | √ |
    | Repeatable read | × | × | √ |
    | Serializable | × | × | × |

六、(掌握)隔离级别详解

1、Read uncommitted

  1. 作用
    所有事务都可以看到其他未提交事务的执行结果
  2. 举个栗子
    又到月底了,小明的老婆要准备给小明发生活费了,小明的老婆给小明打了500块,但该事务并没有提交,而此时小明正好在查余额,发现是550块,高兴的差点蹦了起来.天有不测风云,突然小明的老婆发现多打了50块,于是回滚事务,修改金额,然后将事务提交,最后小明空欢喜异常。
  3. 示例图


    image
  4. 示例代码
    -- ****打开两个窗口 事务A窗口****
    -- 1.查看事务隔离级别
    SELECT @@TX_ISOLATION;
    +------------------+
    | @@tx_isolation   |
    +------------------+
    | READ-UNCOMMITTED |
    +------------------+
    -- 2.设置事务的隔离级别为读取未提交
    SET tx_isolation='READ-UNCOMMITTED';
    -- 3.查看自动提交状态
    SELECT @@AUTOCOMMIT;
    -- 4.如果自动提交开启,关闭自动提交
    SET AUTOCOMMIT = 0;
    --  ****在事务A中执行更新语句,且不提交****
    -- 5. 开启事务
    START TRANSACTION;
    -- 6.  将账户小明的账号的钱减100
    UPDATE account SET  money = money - 100 WHERE aid = 1;
    --  不要提交  切换到事务B的窗口
    -- 7. 事务回滚
    ROLLBACK
    
    -- 事务B窗口
    -- 1. 查看事务的隔离级别
    SELECT @@TX_ISOLATION;
    -- 2.设置事务的隔离级别
    SET TX_ISOLATION = 'READ-UNCOMMITTED';
    -- 3.查询小明的账号
    SELECT * from  account WHERE aid = 1
    -- ****显示的信息****
    +-----+---------+--------+--------+
    | aid | card_no | name   | money  |
    +-----+---------+--------+--------+
    |   1 | 1       | 小明   | 700.00 |
    +-----+---------+--------+--------+
    --  4. 将事务隔离级别设置成读取已提交或者其他
    SET TX_ISOLATION = 'READ-COMMITTED';
    -- 5. 在次查询发现账号余额是800
    SELECT * from  account WHERE aid = 1;
    -- ****显示的信息****
    +-----+---------+--------+--------+
    | aid | card_no | name   | money  |
    +-----+---------+--------+--------+
    |   1 | 1       | 小明   | 800.00 |
    +-----+---------+--------+--------+
    -- 切回事务B 使用回滚 rollback
    

2、Read committed

  1. 作用

    一个事务只能看见已经提交事务所做的改变

  2. 举个栗子

    某个夜黑风高的夜晚,小明丰富的夜生活开始了,小明拿着工资卡去消费,pos机读取卡的信息的时候有500,
    而此时小红也正好在网上转账,把小明工资卡的500元转到另一账户,并小明之前提交了事务,当小明扣款时,
    系统检查到小明的工资卡已经没有钱,扣款失败,小明十分纳闷,明明卡里有钱,为什么会说余额不足,
    出现上述情况,即我们所说的不可重复读,两个并发的事务,“事务1:小明消费”、“事务2:小红网上转账”,事务1事先读取了数据,
    事务2紧接了更新了数据,并提交了事务,而事务1再次读取该数据时,数据已经发生了改变,
    当隔离级别设置为Read committed时,避免了脏读,但是可能会造成不可重复读

  3. 示意图


    image
  4. 备注

    Sql Server ,Oracle的默认级别
    
  5. 示例代码

    -- 事务1
    -- 1. 设置隔离级别为读取已提交
    SET TX_ISOLATION = 'READ-COMMITTED';
    -- 2. 查看当前连接的事务级别
    SELECT @@TX_ISOLATION;
    +----------------+
    | @@TX_ISOLATION |
    +----------------+
    | READ-COMMITTED |
    -- 3. 关闭自动提交
    SET AUTOCOMMIT = 0;
    -- 4. 关闭自动提交
    SELECT @@AUTOCOMMIT;
    -- 5.开启事务
    START TRANSACTION;
    -- 6.账号余额-100
    UPDATE account
    SET account.money= money - 100
    WHERE aid = 1;
    -- 7. 提交事务
    COMMIT
    
    -- 事务1
    -- 1. 设置隔离级别为读取已提交
    SET TX_ISOLATION = 'READ-COMMITTED';
    -- 2. 查看当前连接的事务级别
    SELECT @@TX_ISOLATION;
    -- 3. 关闭自动提交
    SET AUTOCOMMIT = 0;
    -- 4. 关闭自动提交
    SELECT @@AUTOCOMMIT;
     -- 5. 事务1 ******还没有提交事务****
     -- 查询账户信息
    SELECT  * FROM account WHERE aid = 1
    +-----+---------+--------+---------+
    | aid | card_no | name   | money   |
    +-----+---------+--------+---------+
    |   1 | 1       | 小明   | 1000.00 |
    +-----+---------+--------+---------+
    -- 切换到事务1 提交事务
    -- 5. 此时事务已经提交 两次查询的结果不一致
    SELECT  * FROM account WHERE aid = 1
    +-----+---------+--------+--------+
    | aid | card_no | name   | money  |
    +-----+---------+--------+--------+
    |   1 | 1       | 小明   | 900.00 |
    +-----+---------+--------+--------+
    -- 相同的select语句,结果却不一样
    

3、Repeatable read

  1. 说明

    当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时

  2. 举个栗子

    小红最近发现小明总是很晚回家并且经常不接电话,于是小红开始查小明当月信用卡的总消费金额,
    消费金额为50,而小明此时正好在收银台买单,消费1000元,即新增了一条1000元的消费记录,并提交了事务,
    随后小红将小明当月信用卡消费的明细打印了出来,却发现消费总额为1050元,小红很诧异,以为出现了幻觉

  3. 示例图


    image
  4. 备注

    MySQL的默认隔离级别

  5. 区别

    • 不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,
    • 幻读的重点在于新增或者删除比如多次范围读取发现记录增多或减少了。
  6. 示例代码

    -- 事务1
    -- 设置隔离级别
    SET TX_ISOLATION = 'read-committed';
    -- 关闭自动提交
    SET AUTOCOMMIT = 0;
    -- 开启事务
    BEGIN;
    --  插入数据
    INSERT INTO account(card_no, name, money)
    VALUES ('9527', '老李', 0.00);
    -- 切换到事务 2
    
    -- 事务 2
    SET TX_ISOLATION = 'read-committed';
    SET AUTOCOMMIT = 0;
    -- 事务未提交之前
    SELECT * from account
    --
    -- SELECT * from account
    
    image

4、Serializable(禁止使用)

  1. 说明

    最高级别:防止上述3种情况,事务串行执行,慎用
    这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决不读脏,可重复读,不可幻读。
    简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争,并发性能最差,在分布式事务中可能会被用到

七、(了解)更新丢失问题

1、概要

由于RDBMS都有锁机制,所以在并发事务中不存在更新丢失问题

1>加锁阶段:在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得S锁,在进行写操作之前要申请

2>并获得X锁。
加锁不成功,则事务进入等待状态,直到加锁成功才继续执行。
解锁阶段:当事务释放了一个封锁以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作

2、分类

  1. 第一种情况丢失更新:A事务提交时,把已提交的B事务的数据覆盖掉。
  2. 第二钟情丢失更新:A事务回滚时,把已提交的B事务的数据覆盖掉。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 一、(了解)定义 全称(Transaction Control Language)翻译成中文 事务控制语言,事务是...
    唯老阅读 638评论 0 2
  • MySQL 事务的四种隔离级别 1 事务的基本要素(ACID) 原子性(Atomicity):事务开始后所有操作,...
    4a873e424089阅读 641评论 0 0
  • 一、事务概述 我们可以将事务理解为一组sql语句的集合。事务可以只包含一条sql,也可以包含多条sql,事务中所有...
    国球乒乓阅读 354评论 0 0
  • 准备工作了解 mysql -uroot -p123456use test;;系统级隔离级别,如果只是实验系统的可以...
    zhyke阅读 358评论 0 1
  • 什么是事务? 事务是逻辑上的一组操作,要么都执行,要么都不执行。 事务最经典也经常被拿出来说例子就是转账了。 假如...
    赵客缦胡缨v吴钩霜雪明阅读 2,659评论 2 82