相关推荐recommended
MySQL--事务详述
作者:mmseoamin日期:2023-12-25

1. 事务简介

事务是一组操作的集合, 它是一个不可分割的工作单位, 事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求, 即这些操作要么同时执行成功, 要么同时执行失败.  

默认MySQL的事务是自动提交的, 也就是说, 当执行一行DML语句, MySQL会立即隐式的提交事务. 

例如: 一组操作: 张三给李四, 转了1000元.

逻辑单元: 逻辑单元1: 张三账户余额 - 1000元                

                逻辑单元2: 李四账户余额 + 1000元

*
 事务详解:
 例如: 一组操作: 张三给李四, 转了1000元.
逻辑单元: 逻辑单元1: 张三账户余额 - 1000元
        逻辑单元2: 李四账户余额 + 1000元
 */
-- 1.创建表
# 1.1 创建account表
create table account(
    id int primary key auto_increment,
    name varchar(10) not null ,
    money int not null
);
# 1.2 向表中插入数据
insert into account values (null, '张三', 2000),(null, '李四', 2000);
# 1.3 查询数据
select * from account;
# 1.4 恢复到初始金额(张三李四账户金融各2000元)
update account set money = 2000 where name in('张三', '李四');

查询结果: MySQL--事务详述,第1张

2. 事务操作

2.1 程序异常: 当程序出现异常时, 异常后的事务将不会被执行.

例如:

# (转账操作)
-- 2.对于当前来说, 每一条SQL都是一个事务,
# 2.1 查询张三账户余额
select * from account where name = '张三';
# 2.2将张三账户余额 - 1000元
update account set money = money-1000 where name = '张三';
程序输出异常... 
# 此处设置程序输出异常, 则程序执行失败,张三的余额为1000元, 但是李四余额还是2000元.
# 为了解决这种程序异常的问题,我们就需要将张三和李四的转账操作放置在一个 事务中执行.
# 2.3 将李四的账户余额+1000元
update account set money = money + 1000 where name = '李四';

执行结果: MySQL--事务详述,第2张

2.2 事务的操作与两种方式

为了解决程序异常的, 我们需要将该程序相关的事务封装到一个事务中执行.

方式一: 通过关闭事务的自动提交, 通过commit去提交, 通过rollback去回滚事务.

格式:

  • 查看/设置事务的提交方式:
    select @@autocommit;   # 1 是自动提交
    set @@autocommit = 1;  # 0 是手动提交
  • 提交事务:
    commit;
  • 回滚事务(当事务执行过程中出现异常时, 可以回滚事务, 回到执行前的状态):
    rollback ;
    
    -- 3. 将MySQL中的自动提交设置为手动提交
    -- 查看/设置事务的提交方式 (注意: 此处设置的是会话参数, 只针对当前窗口有效)
    select @@autocommit;   # 1 是自动提交
    set @@autocommit = 1;  # 0 是手动提交
    # 3.1 查询张三账户余额
    select * from account where name = '张三';
    # 3.2将张三账户余额 - 1000元
    update account set money = money-1000 where name = '张三';
    # 3.3 将李四的账户余额+1000元
    update account set money = money + 1000 where name = '李四';
    -- 提交事务:
    commit;
    -- 回滚事务(当事务执行过程中出现异常时, 可以回滚事务, 回到执行前的状态)
    rollback ;
    

    方式二: 可以通过指令来开启事务, 通过commit去提交, 通过rollback去回滚事务.

    格式:

    • 开启事务 
      有两种命令: start transaction 或 begin
    • 提交事务:
      commit;
    • 回滚事务:
    • rollback ;
      -- 4. 方式二: 将MySQL中的自动提交设置为手动提交
      # 开启事务 (有两种命令: start transaction 或 begin)
      start transaction ;
      # 4.1 查询张三账户余额
      select * from account where name = '张三';
      # 4.2将张三账户余额 - 1000元
      update account set money = money-1000 where name = '张三';
      # 4.3 将李四的账户余额+1000元
      update account set money = money + 1000 where name = '李四';
      # 提交事务:
      commit;
      # 回滚事务(当事务执行过程中出现异常时, 可以回滚事务, 回到执行前的状态)
      rollback ;

      MySQL--事务详述,第3张

      3. 事务四大特征--ACID

      • 原子性(Atomicity): 事务是不可分割的最小操作单元, 要么全部成功, 要么全部失败.
      • 一致性(Consistency): 事务完成时, 必须使所有的数据都保持一致状态.
      • 隔离性(Isolation): 数据库系统提供的隔离机制, 保证事务在不受外部并发操作影响的独立环境下运行.
      • 持久性(Durability): 事务一旦提交或回滚, 它对数据库中的数据的改变就是永久的.

        4. 并发事务问题

        就是A事务和B事务同时操作一张数据表而引发的问题, 

                1) 脏读: 

        一个事务读到另外一个事务还没有提交的数据

        MySQL--事务详述,第4张

                2) 不可重复读:

        一个事务先后读取同一条记录, 但两次读取的数据不同, 称之为不可重复度.

        MySQL--事务详述,第5张

                3) 幻读:

        一个事务按照条件查询数据时, 没有对应的数据行, 但是在插入数据时, 有发现这样数据已经存在, 好像出现了''幻影'.'

        MySQL--事务详述,第6张

        5. 事务隔离级别

        提示: 就是解决事务并发所引发的问题

        5.1事务隔离级别
        隔离级别脏读不可重复读幻读
        Read uncommitted

        Read committed

        (Oracle默认)

        ×

        Repeatable Read

        (MySQL默认)

        ××
        Serializable×××
        5.2 常用操作
        1) 查看事务隔离级别:
        select @@transaction_isolation;
        2) 设置事务隔离级别
        # 设置当前会话窗口的事务隔离级别
        set session transaction isolation level {Read uncommitted | Read committed | Repeatable Read | Serializable}
        # 设置全局的事务隔离级别
        set global transaction isolation level {Read uncommitted | Read committed | Repeatable Read | Serializable}
        
        5.3 事务隔离级别图解:
        • 在 Read uncommitted级别下,会出现脏读情况: 

          事务B更新没有提交, 但是事务A却读到了数据, 此时读取的就脏数据.

          MySQL--事务详述,第7张

          • 在 Read committed 解决了脏读问题:

            MySQL--事务详述,第8张

            •  在 Read committed 出现了不可重复读的问题:

              MySQL--事务详述,第9张

              •   在 Repeatable Read 解决不可重复读的问题:

                MySQL--事务详述,第10张

                •   在 Repeatable Read 出现了幻读的问题: 

                   MySQL--事务详述,第11张

                  •  在 Serializable 解决了幻读的问题: 

                    MySQL--事务详述,第12张