• 关于X锁的问题--由select+X锁是否持有到事务结束的误区


    前言:看了宋桑的文章《一次意外的X锁不阻塞问题》,结合本人的测试,说明一下我对select中使用X锁是否会持有到事务结束产生的误区;

    详情不多说了,详见宋桑的《一次意外的X锁不阻塞问题》和《消失的共享锁》,对Select+X锁和Select+S锁的情况进行了解释。以下只描述我的测试;测试表结构及数据如下:

     1 /****** Script for SelectTopNRows command from SSMS  ******/
     2 CREATE TABLE [test_a].[dbo].[tmp_byxl_01](id INT IDENTITY,flag int)
     3 INSERT INTO [test_a].[dbo].[tmp_byxl_01](flag) VALUES(null)
     4 go 7
     5 UPDATE [test_a].[dbo].[tmp_byxl_01] SET flag=id 
     6 
     7 SELECT TOP 1000 [id]
     8       ,[flag]
     9   FROM [test_a].[dbo].[tmp_byxl_01]
    10 
    11 
    12 -------------------------------
    13 id          flag
    14 ----------- ----
    15 1           1
    16 2           2
    17 3           3
    18 4           4
    19 5           5
    20 6           6
    21 7           7
    22 
    23 (7 行受影响)

    由于案例出自系统续费问题,业务采用的是调用存储过程的方式实现,因此每一次调用时,都是select+X锁的方式;这和上述文章中提到的“Select+X锁和Select+S锁”的情况不太相同

    先说我的误区

    误区:select中指定的X锁将在查询结束后立即释放,并不持续到tran结束

    测试代码如下:

    --Session_A
    BEGIN TRANSELECT * FROM [test_a].[dbo].[tmp_byxl_01](xlock) WHERE flag=2
      WAITFOR DELAY '00:00:10'
    COMMIT--Session_B
    BEGIN TRANSELECT * FROM [test_a].[dbo].[tmp_byxl_01](xlock) WHERE flag=2
    COMMIT

    由于两个tran都是申请xlock,在执行时,Session_A(spid=53)先执行,Session_B(spid=55)大约5秒后执行,通过SP_LOCK可以看到,spid=55申请X锁时被阻塞

    从执行时间上看,spid(55)晚于spid(53)5秒左右开始,执行时间上基本吻合。

    这个测试验证了上述的误区。加在Select上的X锁持续到了tran结尾,因此才能阻塞其他进程的相同查询(也是Xlock)如此长的时间;

    对于此类情况,一般应用的场景如商家的充值系统、抢购系统等

    需要将大并发的环境转化为单一进程持有锁的情况(select是为了进行判断,如账户起始金额不能为负、或查询当前商品信息以防出现超售的情况)

    对于此类问题,个人认为,增加Xlock进行查询,是为了有效的避免脏读,尽管增加pagelock的方式可以避免S锁的优化问题,但可能导致锁范围过大。

    如果不存在普通S锁的查询,不添加pagelock提升锁级别,也是可以满足大并发需求的。

  • 相关阅读:
    每日总结3.8
    Go中定时器实现原理及源码解析
    Go语言实现布谷鸟过滤器
    详解Go语言调度循环源码实现
    Go语言中时间轮的实现
    详解Go语言I/O多路复用netpoller模型
    详解Go中内存分配源码实现
    Go中由WaitGroup引发对内存对齐思考
    【分享】java精品实战教程
    nginx实战教程
  • 原文地址:https://www.cnblogs.com/diabloxl/p/4227081.html
Copyright © 2020-2023  润新知