zoukankan      html  css  js  c++  java
  • 事务

    事务

    什么是事务

    一个事务是一个完整的业务逻辑单元,不可再分
    比如:银行账户转账,从A账户向B账户转账1000,需要执行两条update语句

    update t_a set balance - 1000 where actno='act-001';
    update t_a set balance + 1000 where actno='act-002';
    

    以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。

    和事务相关的语句只有:DML语句(insert delete update)

    为什么
    因为这三个语句都是和数据库表当中的 数据 相关的。
    事务的存在是为了保证数据的完整性,安全性

    事务的特性?

    事务包括四大特性:ACID
    A:原子性:事务是最小的工作单元,不可再分。
    C:一致性:事务必须保证多条DML语句同时成功或者同时失败
    I:隔离性:事务A与事务B之间具有隔离。
    D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束

    关于事务之间的隔离性

    事务隔离性存在隔离级别,理论上隔离级别包括4个

    • 第一级别:读未提交(read uncommitted)
      • 对方事务还没有提交,我们的当前事务可以读取到对方未提交的数据。
      • 读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据
    • 第二级别:读已提交(read committed)
      • 对方事务提交之后的数据我方可以读取到。
      • 读已提交存在的问题是:不可重复读

    例子:现在A表有5条数据 ABCDE,我读取到5条, 此时对方已经提交了删除 A数据,我现在再去读就变成了 BCDE,如果此时对方又提交了删除B数据,我再去读取就变成了CDE

    • 第三级别:可重复读(repeatable read)

      • 这种隔离级别解决了:不可重复读问题
      • 这种隔离级别存在的问题是:读取到的数据是幻想。
    • 第四级别:序列化读/串行化读(serializable)

      • 事务A与事务B不能并发,只能排队。这种隔离级别最高,效率最低,数据最安全 ,解决了所有问题
      • 问题:效率低,需要事务排队

    使用两个事务演示以上的隔离级别

    第一演示readuncommitted

    设置事务的隔离级别

    set global transaction isolation level read uncommitted;
    

    查看事务的全局隔离级别:

    mysql> select @@global.tx_isolation;
    +-----------------------+
    | @@global.tx_isolation |
    +-----------------------+
    | READ-UNCOMMITTED      |
    +-----------------------+
    1 row in set, 1 warning (0.00 sec)
    
    ## 第二演示read committed读已提交
    

    第一步

    -- 设置事务的隔离级别
    mysql> set global transaction isolation level read committed;
    Query OK, 0 rows affected (0.00 sec)
    -- 查看事务的隔离级别
    mysql> select @@global.tx_isolation;
    +-----------------------+
    | @@global.tx_isolation |
    +-----------------------+
    | READ-COMMITTED        | -- 读已提交
    +-----------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> exit   -- 退出 重进
    Bye
    mysql> use rzk;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    
    
    
    -- 打开两个窗口进行操作
    mysql> start transaction;  -- 打开MySQL在第一个窗口执行
    Query OK, 0 rows affected (0.00 sec)
    mysql> start transaction;  -- 打开MySQL在第二个窗口执行
    Query OK, 0 rows affected (0.00 sec)
    
    
    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    |  2 | lisi     |
    |  3 | lisan    |
    |  4 | lin      |
    |  5 | linkimn  |
    |  6 | waghjn   |
    |  7 | uyjjn    |
    +----+----------+
    7 rows in set (0.00 sec)
    
    

    第二步在第二个窗口进行插入

    mysql> insert into t_user(username) values("rzk");
    Query OK, 1 row affected (0.00 sec)
    

    第三步插入完成后在第一窗口查看有没有插入成功

    mysql> select * from t_user;  -- 可以看到未成功
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    |  2 | lisi     |
    |  3 | lisan    |
    |  4 | lin      |
    |  5 | linkimn  |
    |  6 | waghjn   |
    |  7 | uyjjn    |
    +----+----------+
    7 rows in set (0.00 sec)
    

    第四步在插入的窗口里面进行commit提交

    mysql> commit;
    Query OK, 0 rows affected (0.00 sec)
    

    第五步 返回第一个窗口查询

    mysql> select * from t_user;
    +----+----------+
    | id | username |
    +----+----------+
    |  1 | zhangsan |
    |  2 | lisi     |
    |  3 | lisan    |
    |  4 | lin      |
    |  5 | linkimn  |
    |  6 | waghjn   |
    |  7 | uyjjn    |
    | 10 | rzk      |  -- 此时就可以看到数据已经插入成功
    +----+----------+
    8 rows in set (0.00 sec)
    

    第三演示 repeateble read 可重复读

    设置事务隔离级别

    mysql> set global transaction isolation level repeatable read;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select @@global.tx_isolation;
    +-----------------------+
    | @@global.tx_isolation |
    +-----------------------+
    | REPEATABLE-READ       |
    +-----------------------+
    1 row in set, 1 warning (0.00 sec)
    

    退出,重登

    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    

    在窗口二删除数据,窗口一查看数据
    窗口二 commit; 窗口一的数据还是不会变
    可为什么读到数据了呢,其实读到的是备份数据,幻想,这种就是可重复读

    第四演示serializable

    第一步开启事务

    mysql> set global transaction isolation level serializable;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> select @@global.tx_isolation;
    +-----------------------+
    | @@global.tx_isolation |
    +-----------------------+
    | SERIALIZABLE          |
    +-----------------------+
    1 row in set, 1 warning (0.00 sec)
    
    mysql> exit  -- 重进
    Bye
    
    mysql> start transaction;
    Query OK, 0 rows affected (0.00 sec)
    
    

    可以看到第一条插入,然后在去另一个窗口查询,查询就卡住了,
    必须要等第一个事务执行完毕才能去执行下一个事务

  • 相关阅读:
    全面分析 Spring 的编程式事务管理及声明式事务管理
    100句唤醒自己的励志名言
    100句自我激励的名言佳句
    java反射详解
    JAVA中的反射机制
    【BZOJ1015】【JSOI2008】星球大战Starwar(离线并差集)
    【HEOI2016/TJOI2016】排序(二份答案+线段树)
    【USACO06DEC】—牛奶模式Milk Patterns(后缀自动机)
    【HNOI2016】—找相同字符(后缀自动机)
    【AHOI2013】—差异(后缀自动机)
  • 原文地址:https://www.cnblogs.com/rzkwz/p/13301629.html
Copyright © 2011-2022 走看看