• mysql中的悲观锁和乐观锁


    悲观锁:获取数据时都会直接加锁,共享资源每次只给一个线程使用,其它线程阻塞等待。在数据库中提供了行锁、表锁等,操作数据时先加锁后使用。例如售票系统
    select * from ticket where id=100 for update
    乐观锁:不是数据库系统自带的,需要开发实现。乐观锁是只操作数据时并不进行任何特殊处理,也就是不加锁,在进行更新时才进行冲突判
    在数据表中添加一个额外列: version 数据版本号或者使用时间戳 timestamp ,每次修改数据则版号加1
    update tb_users set age=80,version=2 where id=5 and version=1 第一次读取数据的版本
    号为 1 ,修改时条件为 version=1 的那条数据。如果中间有事务已经修改了数据,则版本号绝
    对不是 1 ,所以该语句执行返回结果为 0
    如果执行结果为 0 ,则重新读取数据,重新执行修改操作
    锁模式
    记录锁:在行相应的索引记录上的锁,锁定一个行记录 . 它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。
    gap 锁:间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一 条索引记录之后的范围
    临键锁 next-key 锁是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
    MYSQL8 RR 级别下默认使用临键锁 . 临键锁的主要目的,也是为了避免幻读 (Phantom Read) 。如果 把事务的隔离级别降级为RC ,临键锁则也会失效
    意向锁:是为了支持多种粒度锁同时存在;
    锁分类
    全局锁:就对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的 MDL DDL 语句、更
    新操作的事务提交语句都将被阻塞。其典型的使用场景是做全库的逻辑备份,对所有的表进行锁
    定,从而获取一致性视图,保证数据的完整性
            flush tables with read lock;
            unlock table
    行级锁
            S 共享锁 :允许获取到此锁的事务读取行
            X 排他锁 :允许获取到此锁的事务 update delete
    表级锁 - 意向锁
            表级锁会对当前操作的整张表加锁,最常使用的 MyISAM InnoDB 都支持表级锁定
            lock tables xxx read/write;
            IS 意向共享锁:事务打算对表中的行设置共享 S
            IX 意向排他锁:事务打算对表中的行设置排他 X
            意向锁是 InnoDB 自动加的, 不需用户干预
    意向锁定协议
            事务在获得表中某行上的共享锁之前,必须先获得表上的IS 锁或更高级别的锁
            在事务可以获得表中某一行上的排他锁之前,它必须首先获得表上的IX
    验证,比如表 aa, 需要开启 set AUTOCOMMIT = FALSE ;
    X: lock tables aa write ;
    S: lock tables aa read ;
    IX: select * from aa where 1 = 2 for update ;
    IS : select * from aa where 1 = 2 lock in share mode ;
    按加锁方式分类
    按加锁方式划分,可分为自动锁、显示锁。
    隐式加锁:
            InnoDB自动加意向锁
            对于UPDATE DELETE INSERT 语句, InnoDB 会自动给涉及数据集加排他锁
            对于普通SELECT 语句, InnoDB 不会加任何锁;
            随时都可以执行锁定,InnoDB 会根据隔离级别在需要的时候自动加锁;锁只有在执行commit或者rollback 的时候才会释放,并且所有的锁都是在同一时刻被释放。
    显式加锁:
            共享锁S SELECT * FROM table_name WHERE … LOCK IN SHARE MODE
            排他锁X SELECT * FROM table_name WHERE … FOR UPDATE
    按照算法分类
    按照算法分类,可分为间隙锁、临键锁、记录锁。
    间隙锁:间隙锁基于非唯一索引,它锁定一段范围内的索引记录。使用间隙锁锁住的是一个区间,
    而不仅仅是这个区间中的每一条数据。 select * from tb_users where id between 1 and 10
    for update ; 即所有在(
    1 10 )区间内的记录行都会被锁住,所有 id 2 3 4 5 6 7 8
    9 的数据行的插入会被阻塞,但是 1 10 两条记录行并不会被锁住
    临键锁是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间,是一个左开
    右闭区间。临键锁的主要目的,也是为了避免幻读 Phantom Read 。如果把事务的隔离级别降级为
    RC ,临键锁则也会失效。每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该
    数据行的临键锁时,会锁住一段左开右闭区间的数据。需要强调的一点是, InnoDB 中行级锁是基
    于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。
    记录锁是封锁记录,记录锁也叫行锁,如 select *from tb_users where id=1 for update ;
    会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。
    相关锁总结
    记录锁、间隙锁、临键锁,都属于排它锁
    记录锁就是锁住一行记录
    间隙锁只有在事务隔离级别 RR 可重复读 中才会产生
            唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁
            普通索引不管是锁住单条,还是多条记录,都会产生间隙锁
            间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现幻读现象
    普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序
    事务级别是 RC 读已提交级别的话,间隙锁将会失效
    表级锁: 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高 , 并发度最低。
    行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低 , 并发度也最高。
    页面锁: 开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度
  • 相关阅读:
    网络安全问题
    Citespace、vosviewer、R语言的文献计量学 、SCI
    RabbitMQ消息发送和接收(实例)
    记一次Postgresql从堆叠注入到RCE
    uniapp开发h5项目引入weixin-sdk报错wx.miniprogram undefined
    Python Excel导入Mysql的通用方法
    org.springframework.test.util.ReflectionTestUtils.invokeMethod方法的使用
    LLaMA Factory单机微调的实战教程
    Ei & Scopus检索 | 2024年第三届能源与环境工程国际会议(CFEEE 2024)
    在windows中安装zipkin报错
  • 原文地址:https://blog.csdn.net/m0_56627229/article/details/127910717