gpt4 book ai didi

.net - LINQ to SQL - 更新以增加非主键字段 - 线程安全

转载 作者:行者123 更新时间:2023-12-02 04:19:22 24 4
gpt4 key购买 nike

我有两个表(嗯,两个与这个问题相关):

投注(持有投注;列:Id、、MessagesPosted、)
Bets_Messages(保存投注的论坛消息;列:Id、BetId、)

当我在 Bets_Messages 中插入新的 BetMessage 时,我想更新(准确地说是递增)Bets 中的相应字段。

在纯 T-SQL 中,这将是:

INSERT INTO Bets_Messages (BetId, <bla bla>) VALUES (23, "asfasdfasdf");
UPDATE Bets SET MessagesPosted = MessagesPosted + 1 WHERE Id = 23;

上面的代码会很好用,而且它是线程安全的;如果两个线程会对它进行 DB 调用(当然对于同一个 Bet),MessagesPosted 列会很好地增加,因为第一个 UPDATE 将至少在其上放置一个 ROWLOCK,实际上是对 UPDATE 进行序列化。

但是,使用 LINQ to SQL 会遇到更困难的方法:
    public void PostMessage(MyProject.Entities.BetMessage betMessageEntity)
{
DatabaseDataContext ctx = GetFreshContext(); // GetFreshContext is a private method that practically initializes a new DataContext
Bets_Message msg = new Bets_Message(betMessageEntity);
ctx.Bets_Messages.InsertOnSubmit(msg);
Bet bet = (from b in ctx.Bets where b.Id == (long)betMessageEntity.BetId select b).Single();
bet.MessagesPosted++;
ctx.SubmitChanges();
}

看起来不错吧?那么这就是它会产生的:
exec sp_executesql N'INSERT INTO [dbo].[Bets_Messages]([ParentMessageId], [BetsId], [UserId], [Subject], [DisplayXml], [Time], [ReplyDepth], [Text])
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7)

SELECT CONVERT(BigInt,SCOPE_IDENTITY()) AS [value]',N'@p0 bigint,@p1 bigint,@p2 uniqueidentifier,@p3 nvarchar(6),@p4 nvarchar(114),@p5 datetime2(7),@p6 tinyint,@p7 nvarchar(8)',@p0=NULL,@p1=1,@p2='A0D253AF-6261-49AE-8C11-BA6117EF35C7',@p3=N'aaawww',@p4=N'<m ai="a0d253af-6261-49ae-8c11-ba6117ef35c7" a="AndreiR" s="aaawww" t="2009-01-31T18:04:31.282+02:00">wwwwwaaa</m>',@p5='2009-01-31 18:04:31.2820000',@p6=0,@p7=N'wwwwwaaa'

(对于 BetMessage 插入)和 UPDATE :
exec sp_executesql N'UPDATE [dbo].[Bets]
SET [MessagesPosted] = @p17
WHERE ([Id] = @p0) AND ([UserId] = @p1) AND ([Bets_CategoriesId] = @p2) AND ([Bets_TypesId] = @p3) AND ([TotalSum] = @p4) AND ([TotalBetters] = @p5) AND ([CreateDate] = @p6) AND ([DeadlineDate] = @p7) AND ([ClosedDate] IS NULL) AND ([Bets_StatusesId] = @p8) AND ([LastBetAdded] IS NULL) AND ([Title] = @p9) AND ([ShortDescription] = @p10) AND ([Description] = @p11) AND ([DescriptionPlainText] = @p12) AND ([Version] = @p13) AND ([ReviewedBy] = @p14) AND ([UrlFragment] = @p15) AND ([MessagesPosted] = @p16) AND ([ClosedBy] IS NULL) AND ([OutcomeNumber] IS NULL)',N'@p0 bigint,@p1 uniqueidentifier,@p2 smallint,@p3 tinyint,@p4 money,@p5 int,@p6 datetime2(7),@p7 datetime2(7),@p8 tinyint,@p9 nvarchar(7),@p10 nvarchar(30),@p11 nvarchar(33),@p12 nvarchar(22),@p13 smallint,@p14 uniqueidentifier,@p15 varchar(7),@p16 int,@p17 int',@p0=1,@p1='A0D253AF-6261-49AE-8C11-BA6117EF35C7',@p2=2,@p3=1,@p4=$0.0000,@p5=0,@p6='2008-12-03 00:00:00',@p7='2008-12-31 00:00:00',@p8=2,@p9=N'Pariu 1',@p10=N'Descriere pariu 1 - text chior',@p11=N'Descriere pe larg 1 - html permis',@p12=N'descriere text chior 1',@p13=1,@p14='A0D253AF-6261-49AE-8C11-BA6117EF35C7',@p15='pariu-1',@p16=18,@p17=19

为 UPDATE 生成的 T-SQL 的问题在于,虽然作为线程安全似乎没问题,但它可能会在第二个线程中引发错误,对行进行更新而不是等待它完成。会吗?

这就是我这么认为的原因。

第一个线程这样做:

插入对应的betMessage,
更新下注行以将 MessagePosted 从 0 增加到 1

第二个线程将执行此操作:

插入它对应的betMessage,
更新下注行以将 MessagePosted 从 0 增加到 1(读取时为 0)。但是现在它是 1 并且 WHERE 子句将使它不更新,因为 wHERE 子句将评估为 false。受影响的 0 行将被发送到 LINQ 客户端,进而引发异常。

因此,我将不得不编写我的 f*#$ing 重试尝试代码,而不是依赖 SQL Server 中的 ROW LOCK。

有没有一些体面的方法使用 LINQ to SQL 和 不是 存储过程、即席查询等等?

感谢您耐心阅读这篇长文。。

最佳答案

编辑 : 实际上重读您的帖子后,我认为 SubmitChanges 生成的自动事务已经负责确保所有语句都完成或没有完成。我在想,由于您使用的是自动生成的 id,您应该在 LINQ 中进行两阶段更新,但似乎 SubmitChanges 会为您处理它。

我将保留下面的代码以供引用,尽管我认为这不是必需的。底部的链接解释了完成交易的不同方式。

您需要的是一个事务范围来包装整个插入/更新集。

using System.Transactions;

public void PostMessage(MyProject.Entities.BetMessage betMessageEntity)
{
using (TransactionScope scope = new TransactionScope()) {
DatabaseDataContext ctx = GetFreshContext();
Bets_Message msg = new Bets_Message(betMessageEntity);
ctx.Bets_Messages.InsertOnSubmit(msg);
ctx.SubmitChanges(); // this is what I thought you did
Bet bet = (from b in ctx.Bets
where b.Id == (long)betMessageEntity.BetId select b)
.Single();
bet.MessagesPosted++;
ctx.SubmitChanges();
scope.Complete();
}
}

我认为这不会导致自动升级到分布式事务,因为所有命令在数据上下文中重用相同的连接。如果确实如此,您可以在数据上下文的连接上创建一个事务并将其分配给数据上下文的 Transaction 属性。但是,如果您这样做,您将需要自己管理和处理它。

有关 LINQ2SQL 和事务的更多信息,请访问 MSDN .

关于.net - LINQ to SQL - 更新以增加非主键字段 - 线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/499130/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com