MySQL第十二篇-----事务

版权声明:未经本人同意不得转载 https://blog.csdn.net/object_oriented_/article/details/88115998

        1. 事务的基本介绍
                 如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
            
        2. 操作:
            1. 开启事务: start transaction;
            2.  回  滚:rollback;
            3.  提  交:commit;
     

  3.案例:张三给李四转500元

                       张三余额是否够500
                       张三  -500
                       异常
                       李四 +500                   

CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);
            
SELECT * FROM account;

                

正常情况:

UPDATE account SET balance = balance - 500 WHERE NAME='zhangsan';

UPDATE account SET balance = balance + 500 WHERE NAME='lisi';

         

异常情况:

UPDATE account SET balance = balance - 500 WHERE NAME='zhangsan';
出错啦!
UPDATE account SET balance = balance + 500 WHERE NAME='lisi';

      

出现这个问题是因为在汉字的地方被当成 SQL 语句执行了,zhangsan已经转账500, 而lisi却没有收到500
解决: 需要用到事务解决
 UPDATE account SET balance = 1000; -- 复原账务

关于事务的情况

第一种情况: 异常情况下, 开启了事务,不进行提交,不进行回滚 

-- 开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
出现异常了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';

             

 结果: 数据发生临时变化,打开两个窗口时,另一个窗口数据是不变的,或者 重启发生数据改变的SQLyog工具后临时变化前的数据

第二种情况 正常情况下 不提交事务也不需要回滚

--  开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
-- 出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';

 结果:  转账成功, 另一个窗口没有进行转账,重启转账成功的窗口发现转账是临时的操作,原因是没有进行提交事务

第三种情况: 正常情况下.提交事务

-- 开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
-- 出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
-- 发现执行没有问题,提交事务
COMMIT;

 结果: 在正常情况下转账成功, 事务进行了提交, 两个页面查询都正常转账,重启后转账也显示成功

第四种情况,异常情况下进行回滚事务 不提交

-- 开启事务
START TRANSACTION;

-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';

-- 李四账户 +500
出现异常了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';

-- 发现出问题了,回滚事务
ROLLBACK;

 结果:转账不成功,数据不变,事务回到了回滚开启事务的地方


第五种情况: 数据正常, 开启事务 ,提交事务, 回滚事务

-- 开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
-- 出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
-- 发现执行没有问题,提交事务
COMMIT;
-- 发现出问题了,回滚事务
ROLLBACK;

  结果: 转账成功并提交事务

第六种情况:数据异常, 开启事务 ,提交事务, 回滚事务

-- 开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
-- 发现执行没有问题,提交事务
COMMIT;
-- 发现出问题了,回滚事务
ROLLBACK;

结果: 转账异常 张三进行了-500, 李四没有+500 ,事务进行了提交,没有回滚

第七种情况: 数据异常, 开启事务 ,回滚事务,提交事务 (注意和第六种情况的顺序不同)

-- 开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';

-- 发现出问题了,回滚事务
ROLLBACK;

-- 发现执行没有问题,提交事务
COMMIT;

问题: 错误的情况下进行转账回滚事务, 达到了预期结果,错误就进行了事务回滚


第八种情况: 数据正常, 开启事务 ,回滚事务,提交事务 (注意和第六种情况的顺序不同)

-- 开启事务
START TRANSACTION;
-- 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 李四账户 +500
-- 出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';

-- 发现出问题了,回滚事务
ROLLBACK;

-- 发现执行没有问题,提交事务
COMMIT;

结果: 正确的数据下转账应该成功却没有成功,数据没有变化,也就是说回滚关键字起作用了


总结:
问题: 错误的情况下进行转账回滚事务,为什么正确的数据下还是回滚了,这个ROLLBACK和COMMIT不能同时存在吗?

注意: 两个关键字是不能同时存在的,要么进行了提交, 要么进行了回滚,    二选一

 4. MySQL数据库中事务默认自动提交
           1)事务提交的两种方式:
                 自动提交:
                      mysql就是自动提交的
                      一条DML(增删改)语句会自动提交一次事务。例如进行update 更改一条数据 ,自动提交了事务, 数据会持久化更新
                      手动进行了开启事务(start transaction;),就需要手动提交事务(commit;)
                  手动提交:
                      Oracle 数据库默认是手动提交事务
                      需要先开启事务,再提交
            2) 修改事务的默认提交方式:
                  查看事务的默认提交方式:SELECT @@autocommit; -- 1 代表自动提交  0 代表手动提交
                            
                  修改默认提交方式: set @@autocommit = 0;
                            
                   验证:  修改事务提交方式为0(手动提交),表account的原数据中是1000
                            进行更改数据为888,修改后因为不是自动提交事务,关闭SQLyog再打开查看数据还是原来的1000
                             重新打开,查询后数据如下图:    
                            

                                       
    5. 事务的四大特征:
        1) 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
        2) 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
        3) 隔离性:多个事务之间。相互独立。
        4) 一致性:事务操作前后,数据总量不变
    6. 事务的隔离级别(了解)
           概念:多个事务之间是隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
          存在问题:
            1. 脏读:一个事务,读取到另一个事务中没有提交的数据( 另一个数据没有进行提交就读到了,很严重的问题)
            2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
            3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
          隔离级别:
            1. read uncommitted:读未提交
                                               产生的问题:脏读、虚读、幻读
            2. read committed:读已提交 (Oracle)
                                               产生的问题:虚读、幻读
            3. repeatable read:可重复读 (MySQL默认)
                                               产生的问题:幻读
            4. serializable:串行化
                                              可以解决所有的问题

             注意:隔离级别从小到大安全性越来越高,但是效率越来越低
               数据库查询隔离级别:
                                      select @@tx_isolation;
                                     
               数据库设置隔离级别:
                                set global transaction isolation level  隔离级别字符串;
                      

验证1:把事务的隔离级别设置成read uncommitted:读未提交
            set global transaction isolation level read uncommitted;
           
设置隔离级别后,连接需要断掉,重新打开sqlyog才会生效;
                 

  第一步:   打开两个窗口, 都是原数据1000, 都手动提交事务   start transaction;
                         第一个窗口进行-- 转账操作
                          update account set balance = balance - 500 where id = 1;
                          update account set balance = balance + 500 where id = 2;
  第二步:  第一个窗口并未提交事务,查询第二个窗口, 转账成功, 读未提交隔离级别生效, 数据查到变化这是发生了脏读
               第二个窗口读到了第一个窗口没有提交的数据,脏读发生了
               此时第一个窗口没有提交而是进行了回滚操作rollback,数据还原到转账前的操作,第二个窗口的数据变回去了
               脏读发生了,不可重复读(虚读)也发生了, 第一个窗口查到的数据不一样
               幻读在MySQL中演示不出来
              
验证2:把事务的隔离级别设置成read committed;读已提交  解决脏读,但是还有虚读
             set global transaction isolation level read committed; -- 设置隔离级别
             select @@tx_isolation; -- 查询隔离级别
     第一步: 打开两个窗口: 都开始事务START TRANSACTION;,数据都是1000
     第二步: 转账
                 UPDATE account SET balance = balance - 500 WHERE id=1;
                 UPDATE account SET balance = balance + 500 WHERE id=2';
                 第一个窗口进行转账操作, 第二个窗口查不到转账还是原来的数据1000,
                 需要第一个窗口进行提交事务,第二个窗口才可以查到, 解决了脏读问题
                 
                 第二个窗口第一次查到的是1000,1000 第二次查到的是500, 1500 存在不可重复读
验证3:把事务的隔离级别设置成repeatable read;可重复读  解决脏读,虚读,还存在幻读
                 set global transaction isolation level repeatable read; -- 设置隔离级别
                 select @@tx_isolation; -- 查询隔离级别
                  数据复原1000,都开启事务
           第一步:  第一个窗口开启了事务,第二个窗口也开启了事务
                         第一个窗口进行转账操作,未提交事务
                         UPDATE account SET balance = balance - 500 WHERE id=1;
                         UPDATE account SET balance = balance + 500 WHERE id=2';
                         第二个窗口查询是1000,1000
            第二步: 第一个窗口进行了提交commit, 第二个窗口进行查询还是1000,1000
                        第二个窗口可重复读隔离级别生效了,两次查询的结果都是一样的
                        在同一个事务中(两个窗口分别各开启了事务), 当在第二个窗口提交事务后或者回滚后才可以查到数据变化
                            
验证4:把事务的隔离级别设置成serializable; 串行(hang)化  解决脏读,虚读,幻读
                串行化就是锁表的动作,如果一个事务在操作一张表,另外一个事务是不能操作这张表的
                只有当这把锁打开之后另外一个事务才可以操作
              set global transaction isolation level serializable; -- 设置隔离级别
              select @@tx_isolation; -- 查询隔离级别
              数据复原1000,都开启事务
        第一步:都开启了事务 第一个窗口转账操作,未提交, 第二个窗口进行查询,并没有执行查询语句一直在等待 
                   这是因为串行化隔离级别生效了,只有第一个窗口进行了回滚或者是提交之后才可以进行查询
                  
         第一个窗口进行提交事务(释放锁)后, 第二个窗口才可以进行查询数据

                

     第一个把锁给锁上了,只能在这个事务下操作,别的开启事务后只有等待,效率很低
     所以隔离级别越来越安全,效率越来越低
 

                                                                            <事务完 >

猜你喜欢

转载自blog.csdn.net/object_oriented_/article/details/88115998