喂,
我的Web服务有多个可以调用的方法。每次调用其中一个方法时,我都会将调用记录到统计数据库中,这样我们就知道每个方法每个月调用多少次以及平均处理时间。
每次我记录统计数据时,我首先检查数据库以查看当前月份的方法是否已经存在,如果不是,则创建并添加该行。如果它已经存在,我将所需的列更新到数据库。
我的问题是,有时当我更新一行时,我得到“未找到或未找到行”异常,是的,我知道这是因为自从我阅读以来该行已被修改。
要解决此问题,我尝试使用以下内容但未成功:
下面我添加了用于记录统计数据的代码。非常感谢任何帮助。
public class StatisticsGateway : IStatisticsGateway
{
#region member variables
private StatisticsDataContext db;
#endregion
#region Singleton
[ThreadStatic]
private static IStatisticsGateway instance;
[ThreadStatic]
private static DateTime lastEntryTime = DateTime.MinValue;
public static IStatisticsGateway Instance
{
get
{
if (!lastEntryTime.Equals(OperationState.EntryTime) || instance == null)
{
instance = new StatisticsGateway();
lastEntryTime = OperationState.EntryTime;
}
return instance;
}
}
#endregion
#region constructor / initialize
private StatisticsGateway()
{
var configurationAppSettings = new System.Configuration.AppSettingsReader();
var connectionString = ((string)(configurationAppSettings.GetValue("sqlConnection1.ConnectionString", typeof(string))));
db = new StatisticsDataContext(connectionString);
}
#endregion
#region IStatisticsGateway members
public void AddStatisticRecord(StatisticRecord record)
{
using (db)
{
var existing = db.Statistics.SingleOrDefault(p => p.MethodName == record.MethodName &&
p.CountryID == record.CountryID &&
p.TokenType == record.TokenType &&
p.Year == record.Year &&
p.Month == record.Month);
if (existing == null)
{
//Add new row
this.AddNewRecord(record);
return;
}
//Update
existing.Count += record.Count;
existing.TotalTimeValue += record.TotalTimeValue;
db.SubmitChanges();
}
}
答案 0 :(得分:1)
我建议让SQL Server处理并发问题。
以下是:
创建一个存储过程,接受您的日志值(方法名称,月份/日期和执行统计信息)作为参数。
在存储过程中,在其他任何事情之前,获取应用程序锁定为described here,and here。现在您可以确保只有一个存储过程实例将一次运行。 (免责声明!我自己没有试过sp_getapplock
。只是说。但是看起来相当简单,因为互联网上有所有的例子。)
接下来,在存储过程中,查询日志表以获取方法的当前月份条目,以确定是否插入或更新,然后执行插入或更新。
您可能知道,在VS中,您可以将存储过程从Server Explorer拖到DBML设计器中,以便使用LINQ to SQL轻松访问。
如果你试图避免存储过程,那么这个解决方案显然不适合你,但这就是我如何轻松快速地解决它。希望它有所帮助!
答案 1 :(得分:0)
如果您不想使用存储过程方法,那么处理它的粗略方法就是重试该特定异常。 E.g:
int maxRetryCount = 5;
for (int i = 0; i < maxRetryCount; i++)
{
try
{
QueryAndUpdateDB();
break;
}
catch(RowUpdateException ex)
{
if (i == maxRetryCount) throw;
}
}
答案 2 :(得分:0)
我没有使用sp_getapplock,而是使用了HOLDLOCK和ROWLOCK,如下所示:
CREATE PROCEDURE [dbo].[UpdateStatistics]
@MethodName as varchar(50) = null,
@CountryID as varchar(2) = null,
@TokenType as varchar(5) = null,
@Year as int,
@Month as int,
@Count bigint,
@TotalTimeValue bigint
AS 开始 SET NOCOUNT ON;
BEGIN TRAN
UPDATE dbo.[Statistics]
WITH (HOLDLOCK, ROWLOCK)
SET Count = Count + @Count
WHERE MethodName=@MethodName and CountryID=@CountryID and TokenType=@TokenType and Year=@Year and Month=@Month
IF @@ROWCOUNT=0
INSERT INTO dbo.[Statistics] (MethodName, CountryID, TokenType, TotalTimeValue, Year, Month, Count) values (@MethodName, @CountryID, @TokenType, @TotalTimeValue, @Year, @Month, @Count)
COMMIT TRAN
END GO
我已经通过多个线程同时调用我的Web服务方法来测试它,并且每次调用都没有任何问题。