• 数据库基础02-MYSQL的事务


    Mysql的事务

    1.基本概念

         事务本质是一组SQL操作,事务中的语句要么全部执行成功,或者全部执行失败。

    2.如何保证一个事务:四个特性(ACID)

    原子性 (Automic)

         表示事务是操作的最小单元。整个事务的操作,要么全部成功,要么全部失败。

    一致性 (consistency)

         数据库总是从一个状态转换成另一个状态。
    当事务中间执行错误时,事务会回滚到执行事务之前的状态。如果整个事务执行成功,才能成为成功的状态。

    隔离性 (isolation)

         一般来说,一个事务在提交操作之前对其他事务是不可见的。
    在事务中的操作完成提交之后,其他的事务才能看到当前对数据库的修改。当然这只是一般状态,因为隔离级别的不同,可能会存在差异。

    持久性 (durablity)

         一个事务执行成功,其所对数据库所进行的修改会永久的保存到数据库中。

    3.Mysql的事务操作

    开始事务
      start transaction; 
      set autocommit=0;
    
    提交事务 commit;
    回滚事务 rollback;
     - mysql 默认不开始事务,需要手动启动事务
    
     - 每一步数据修改都直接生效
    
     - 查看事务是否开启
    
            show variables like 'autocommit';                    
    

    4.事务的可见性控制:隔离级别

         不同数据库及数据引擎可能会有不同,以innodb数据库引擎为准

    四种隔离级别:

    • READ UNCOMMITED(读未提交) 事务中的修改,即使没有提交,其他事务也能看到;
    • READ COMMITED (读已提交) 一个事务只能看到提交的事务做出的修改;
    • REPEATED READ (可重复读) 保证多次读取同样的记录是一致的。MYSQL的默认隔离级别
    • SERIALIZABLE (序列化) 强制让事务串行执行,会给读取的每一行数据都加上锁,所以会造成锁竞争,出现超时情况。

    隔离级别的设置:

    set tx_isolation='READ-UNCOMMITTED';
    set tx_isolation='read-committed';
    set tx_isolation='repeatable-read';
    set tx_isolation='serializable';
    
    查看隔离级别
    select @@transaction_isolation
    

    访问冲突情况

    隔离级别 访问冲突现象
    read-uncommitted 脏读,幻读,不可重复读
    read-committed 幻读,不可重复读
    repeatable-read 幻读
    serializable 序列化,完全隔离(同一个表,只能一个事务处理)

    脏读:
         可以读取其他事务未提交的数据

    客户端1 客户端2
    set tx_isolation='read-uncommitted'; set tx_isolation='read-uncommitted';
    rollback;begin; rollback;begin;
    Insert into tb1(name)values('bb'); Select * from tb1;
    Update tb1set name='a'where id=1; Select * from tb1;
    rollback; Select * from tb1;

    不可重复读:
         其他事务对当前事务查询范围数据进行了的修改,在其他事务提交后,查询到的是修改后的数据。因为在其他事务提交之前和其他事务提交之后查询的结果不一致,因此也就是不可重复读。

    客户端1 客户端2
    select @@transaction_isolation
    set transaction_isolation='read-committed'
    select @@transaction_isolation
    set transaction_isolation='read-committed'
    begin begin
    select * from temp (图一)
    update temp set name='zhangsan' where name='zs'
    select * from temp
    commit
    select * from temp(图二)
    commit

    图一:

    图二:

    幻读:
    幻读,又叫做幻行。指在当前事务查询的范围内,其他事务进行了增删操作,当再次查询的时候就会出现幻行的情况。

    客户端1 客户端2 客户端3
    select @@transaction_isolation
    set transaction_isolation='repeatable-read'
    select @@transaction_isolation
    set transaction_isolation='repeatable-read'
    select @@transaction_isolation
    set transaction_isolation='repeatable-read'
    begin begin begin
    select * from temp(图一)
    delete from temp where name ='lisi'
    commit
    select * from temp(图二)
    insert into temp (id,name)values(uuid(),'xiaohong');
    commit
    select * from temp(图三)
    commit

    图一:

    图二:

    图三:

    5.事务的资源竞争:锁

    5.1 Mysql的锁和引擎有关系
    • innodb默认使用的是行级锁
    一个事务修改一行数据未提交时, 该行数据会被锁定,不允许其他事务修改
    
    • myisam 默认使用的是表级锁
    5.2 死锁

    出现场景:当两个事务或多个事务在统一资源上占用,并请求对象占用的资源,造成了恶行循环;

    事务一
    start transaction
    update temp set username='zhangsan' where username='zs'
    update temp set username='ls' where username='lisi'
    
    事务二
    start transaction
    update temp set username='lsj' where username='lisi'
    update temp set username='zhangsanfeng' where username='zs'
    
    
    5.2 几种常见的数据库锁
    乐观锁
    乐观锁,通常不是数据库自带,通过自己实现;
    实现的过程一般为:
    例子:
     在修改信息当前,判断versions,和之前存储的versions编号进行比对,看是否一致
    1.查询要修改数据的标志(sign)
    select name,sign  from temp where id='666'
    2.修改要调整的数据,判断sign是否和之前的查询数据一直,如果一直则更新;
    update temp set name='wangwu',sign=sign+1 where id='666'and sign='之前的sign'
    
    
    悲观锁

    在整个数据处理过程中,将数据处于锁定状态

    悲观锁的实现:
    
    1. 自动提交模式要关闭
    set autocommit = 0;
    当执行一个sql时,数据库立即执行;
    
    2. 开启事务
    begin;/begin work;/start transaction;
    
    3. 查询要操作数据的信息
    SELECT * FROM TB WHERE CD FOR UPDATE
    
    FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据会等其他数据执行完毕后再执行
    
    4.数据进行插入操作等
    insert into t_orders (id,goods_id) values (null,1);
    
    5.更新插入数据列状态
    update t_goods set status=2;
    
    6.提交SQL执行
    commit;/commit work;
    手动对需要执行的SQL进行提交;
    
    

    不过我们需要注意一些锁的级别,MySQL InnoDB默认Row-Level Lock,所以只有「明确」地指定主键,MySQL 才会执行Row lock (只锁住被选取的数据) ,否则MySQL 将会执行Table Lock (将整个数据表单给锁住)。

    明确指定了主键,并且有该数据,row lock
    console1:
            BEGIN;
            SELECT * FROM city WHERE id='1' FOR UPDATE 
    
      |id|name|state|
        |:--|---:|:--:|
        |1|美国|0|
    
    console2:
            BEGIN;
            SELECT * FROM city WHERE id='1' FOR UPDATE 
    

    查询被阻塞;

    报错:error:1205
    Lock wait timeout exceeded; try restarting transaction

    明确指定主键,若查无此数据,无lock
    console1:查询结果为空;
    console2:查询结果为空,查询无阻塞,说明console1没有对数据执行锁定
    
    主键不明确,table lock
    console1:查询正常
        BEGIN ;
        SELECT * FROM city  WHERE id !='3' FOR UPDAT;
    
    id name state
    1 美国 0
    2 新加坡 0
    console2:查询被阻塞,说明console1把表锁住了
        BEGIN;
        SELECT * FROM city WHERE id ='1' FOR UPDATE
    

    共享锁

    console1: 查询没有问题
          BEGIN;
          select * from city WHERE ID='1' LOCK IN SHARE MODE
    console2:查询阻塞报错;
          select * from city  WHERE ID='1'
    console2:查询没有问题
          select * from city  WHERE ID='1' LCOCK IN SHARE MODE
    
    用的共享锁,可以查询同一行数据,但是不能进行insert,update等操作,因为这些操作会单独在次进行锁的判断
    
    

    排它锁

    console1:查询无误
        BEGIN;
        SELECT * FROM CITY WHERE ID='1' FOR UPDATE
    console2:阻塞状态
        SELECT * FROM CITY WHERE ID='1'
    console2:阻塞状态
        SELECT * FROM CITY WHERE ID='1' FOR UPODATE
    

    共享锁和排它锁更像是悲观锁的一个分类;

    参考博客:https://blog.csdn.net/puhaiyang/article/details/72284702

  • 相关阅读:
    HDU5029--Relief grain (树链剖分+线段树 )
    codeforces 277.5 div2 F:组合计数类dp
    FZU2176---easy problem (树链剖分)
    Codeforces Round #277.5 (Div. 2) --E. Hiking (01分数规划)
    FZU 11月月赛D题:双向搜索+二分
    POJ
    POJ
    HDU 4746 Mophues(莫比乌斯反演)
    BZOJ 2005 能量采集 (莫比乌斯反演)
    BZOJ 2301 Problem b (莫比乌斯反演+容斥)
  • 原文地址:https://www.cnblogs.com/perferect/p/13098662.html
Copyright © 2020-2023  润新知