我有一个表,用于跟踪客户使用情况。我跟踪用户每天的点击次数,因此我有一个如下表:
CustID (uniqueidentifier, not null)
UseDate (smalldatetime, not null)
NumHits (smallint, not null)
我在存储的proc中使用此SQL来为今天(如果需要)插入一行,或为今天增加计数器:
declare @today datetime
set @today = getdate()
/* Try to bump it by one if an entry for today exists */
if (
select count(*) from CustomerUsage
where CustID = @cust_guid and year(UseDate) = year(@today) and month(UseDate) = month(@today) and day(UseDate) = day(@today)
) = 0
insert into CustomerUsage (CustID, UseDate, NumHits) values (@cust_guid, getdate(), 1)
else
update CustomerUsage set NumHits = NumHits + 1
where CustID = @cust_guid and year(UseDate) = year(@today) and month(UseDate) = month(@today) and day(UseDate) = day(@today)
有一个更好的方法吗?
另外,我想移至多个Web服务器可以为同一客户调用存储的proc的环境。我认为这段代码可能容易受到多线程问题的影响。
谢谢!
最佳答案
你可以这样
declare @Today smalldatetime = dateadd(d, datediff(d, 0, getdate()), 0)
declare @Tomorrow smalldatetime = dateadd(d, 1, @Today)
insert into CustomerUsage(CustId, UseDate, NumHits )
select Data.CustID, Data.UseDate, Data.NumHits
from (select
@cust_guid as CustID,
getdate() as UseDate,
0 as NumHits) as Data
where not exists (select *
from CustomerUsage with (updlock, serializable)
where
CustID = @cust_guid and
UseDate >= @Today and
UseDate < @Tomorrow)
update CustomerUsage
set NumHits = NumHits + 1
where
CustID = @cust_guid and
UseDate >= @Today and
UseDate < @Tomorrow
首先使用
NumHits = 0
插入一行。插入检查该CustID
上是否已经存在该UseDate
的行,并且仅在必要时插入。插入之后,请始终将
NumHits
递增1。这基本上与托马斯非合并答案相同,但是我在更新之前进行了插入。
编辑1 向插入语句
where not exists
部分添加了表提示。需要serializable
来防止违反主键约束,并且需要updlock
来避免死锁。
关于sql - 使TSQL插入/更新即使在多线程的情况下也能正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5059826/