【问题标题】:How can I make a stored procedure commit immediately?如何立即提交存储过程?
【发布时间】:2013-04-19 10:01:16
【问题描述】:

编辑此问题不再有效,因为问题是其他问题。请在我的回答中查看我的解释。

我不确定礼仪,所以我将把这个问题留在当前状态

我有一个将一些数据写入表的存储过程。

我正在使用 Microsoft Practices Enterprise 库进行存储过程调用。 我使用对 ExecuteNonQuery 的调用来调用存储过程。

在 ExecuteNonQuery 返回后,我调用了第 3 方库。它会在大约 100 毫秒后在一个单独的线程上回调给我。

然后我调用另一个存储过程来提取我刚刚写入的数据。 在大约 99% 的情况下,数据会返回。有时它不返回任何行(即它找不到数据)。如果我在调试器中设置条件断点来检测这种情况并手动重新运行存储过程,它总是会返回我的数据。

这让我相信写入存储过程正在工作,只是在调用时没有提交。

我在 sql 方面相当新手,所以我完全有可能做错了什么。我原以为写入存储过程会阻塞,直到其内容提交到数据库。

编写存储过程

 ALTER PROCEDURE [dbo].[spWrite] 
    @guid varchar(50),
        @data varchar(50)
    AS
    BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

-- see if this guid has already been added to the table
DECLARE @foundGuid varchar(50);
SELECT @foundGuid = [guid] from [dbo].[Details] where [guid] = @guid; 
    IF @foundGuid IS NULL
    -- first time we've seen this guid
    INSERT INTO [dbo].[Details] ( [guid], data ) VALUES (@guid, @data)
ELSE
    -- updaeting or verifying order
    UPDATE [dbo].[Details]  SET data =@data WHERE [guid] = @guid
END


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

读取存储过程

ALTER PROCEDURE [dbo].[spRead] 
@guid varchar(50)   
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

SELECT * from [dbo].[Details] where [guid] = @guid; 
END 

【问题讨论】:

    标签: sql-server acid


    【解决方案1】:

    要真正阻止其他事务并手动提交, 可能会添加

    BEGIN TRANSACTION
    --place your
    --transactions you wish to do here
    
    --if everything was okay
    COMMIT TRANSACTION
    --or
    --ROLLBACK TRANSACTION if something went wrong
    

    可以帮到你吗?

    【讨论】:

    • 感谢您的意见。如果有帮助,我可以使用事务,但在我明白为什么需要之前我真的不想这样做。在这种情况下,交易将如何帮助?它会让数据库在处理该表上的任何其他查询之前强制提交吗?
    • 是的,这会强制提交,您可能会检查的另一件事(也许不是:))是第二次调用是否真的在您的第一次调用之后出现(因为您说它来自不同的线程)
    • 这是强制提交的正确方法。但是,它不一定会导致其他查询阻塞,因为这也受其他因素(隔离级别、查询类型、事务状态、涉及的数据等)控制。
    【解决方案2】:

    我不熟悉您提到的数据访问工具,但根据您的描述,我猜该进程不会等待存储过程完成执行,然后再继续下一步,或者是“其他” ”在你的 write 和 read 调用之间弄乱了数据。

    判断发生了什么的一种方法是使用 SQL Profiler。启动它,监视数据库上所有可能的查询执行事件(包括存储过程和存储过程行开始/停止事件),观察 Text 和 Started/Ended 列,将其与跟踪应用程序时看到的时间相关联,以及这应该可以帮助您弄清楚那里发生了什么。 (SQL Profiler 使用起来可能很复杂,但网络上有很多资源可以解释它,学习如何使用它非常值得。)

    【讨论】:

      【解决方案3】:

      我会在下面留下我的答案,因为上面有 cmets...

      好的,我很遗憾我把我的问题简化得太多了。实际发生的是两件事:

      1) 插入过程实际上是在单独的机器(分布式系统)上运行的。
      2) 插入过程实际上是在没有事务的情况下将数据插入到两个表中。

      这意味着查询可以同时运行并查找处于其中一个表已写入但第二个表尚未提交其写入的状态的表。

      一个简单的事务解决了这个问题,因为读取查询可以处理无写入或完全写入的情况,但无法处理一个表已写入而另一个表有待提交的情况。

      事实证明,当我创建存储过程时,MSSQLadmin 工具默认添加了一行:

      SET NOCOUNT ON;
      

      如果我把它变成:

      SET NOCOUNT OFF;
      

      然后我的程序实际上正确地提交到数据库。奇怪的是,这种默认设置实际上最终会导致问题。

      【讨论】:

      • 您有多确定 NOCOUNT 设置是问题的根源?这似乎极不可能。
      • @Nick 我还不能 100% 确定,我只能说,如果我打开此设置,我可以在大约 1,000 次试验后重现该问题,关闭它我无法重现此问题100,000 次试验后的问题。像所有的科学一样,我不能很好地反驳否定,我只能说我还不能重现这个问题。
      • 听起来你有一个竞争条件。只需从同一个线程读取和写入。
      • @Nick 我相信你对竞争条件的看法是正确的,但我不能从同一个线程读写。让我们把它作为一个约束。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 2014-04-07
      • 1970-01-01
      • 2014-01-31
      • 1970-01-01
      相关资源
      最近更新 更多