首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SQL死锁-相同的存储过程调用并发

SQL死锁-相同的存储过程调用并发
EN

Database Administration用户
提问于 2019-12-13 14:44:35
回答 2查看 1.8K关注 0票数 4

我正在使用一个相对复杂的系统,在这个系统中,静态表根据需要从多个数据源更新,因为动态加载数据需要4-5秒,我们更喜欢快速地向用户显示结果。

这一进程:

  1. 用户或应用程序打开特定的订单。
  2. 调用存储过程来提取数据(让我们称其为dbo.Get_Data)
  3. dbo.Get_Data检查事件日志,以确定自上次查找数据以来是否有任何更改。
  4. 如果它找到一个新事件,它将运行昂贵的查询来更新数据。
  5. 数据被返回
代码语言:javascript
复制
IF (
    SELECT [LastStaticUpdateEvent] < [LastSaveEvent] 
    FROM [dbo].[Events] 
    WHERE [OrderNumber] = @OrderNumber
)
BEGIN
    -- Update Static table
    UPDATE [Static]
    SET [Static].[A] = [App].[A]
        ,[Static].[B] = [App].[B]
    FROM [dbo].[AppData] AS [App] -- View with many joins (4-5 secs)
    INNER JOIN [dbo].[StaticResuts] AS [Static]
        ON [Static].[OrderNumber] = [App].[OrderNumber]
    WHERE [App].[OrderNumber] = @OrderNumber

    -- Update Event Log
    UPDATE [dbo].[Events]
    SET [LastStaticUpdateVent] = SYSDATETIME()
    WHERE [OrderNumber] = @OrderNumber
END

SELECT * FROM [dbo].[StaticResults]

问题是可以同时请求这些数据。如果用户A和用户B都在第一次更新完成之前调用dbo.Get_Data,则会发生死锁。

是否有一个好的方法或模式让第二次呼叫等待到第一次完成,然后继续其查找?

EN

回答 2

Database Administration用户

回答已采纳

发布于 2019-12-13 16:03:05

是否有一个好的方法或模式让第二次呼叫等待到第一次完成,然后继续其查找?

一次只能运行一个会话的代码块的最简单方法是使用应用锁。您可以使用Server的锁定引擎,但不是锁定特定的行、页或表,而是创建带有自定义名称的锁。例如

代码语言:javascript
复制
begin transaction;

--begin exclusive section
exec sp_getapplock @Resource = 'Get_Data Exclusive Lock', @LockMode = 'Exclusive';  

--do stuff in only one session

--end exclusive section
exec sp_releaseapplock @Resource = 'Get_Data Exclusive Lock';  


commit transaction;
票数 9
EN

Database Administration用户

发布于 2019-12-19 22:44:07

简单的修复可以是WITH (NOLOCK)

代码语言:javascript
复制
SELECT * FROM [dbo].[StaticResults] WITH (NOLOCK)

这意味着您不会被进程中的并发事务阻塞,即使锁在表上,进程也会读取表数据。结果可能是用户在该尝试中看不到更新的数据。只要它不是金融交易或商业关键交易,它就能达到目的。

票数 -4
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/255585

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档