我正在使用Entity Framework 6 Database.SqlQuery语句执行存储过程。我想防止两个用户同时执行相同的存储过程。
答案 0 :(得分:4)
您可以通过两种方法解决此问题:
1)如果您只想锁定特殊的存储过程,则可以使用如下字典:
start end move
0 5 1 // the start value here is the lowest of the next 5 end values
5 10 1 // same as above
10 15 1 // same as above
15 25 1 // same as above
25 30 1 // same as above
30 35 0 // end goes up and down so 0 here
35 40 0 // same as above
40 30 -1 // next are all below 40 so -1 now
30 20
20 15
15 10
10 5
2)另外,您还可以确保每个存储过程都执行一次。添加以下代码以启动存储过程。
static Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public List<TResult> ExecuteStoredProcedureWithLock<TResult>(string storedProcedureName, object parameters) where TResult : new()
{
lock (_dictionary)
{
if (_dictionary.ContainsKey(storedProcedureName) == false)
{
_dictionary.Add(storedProcedureName, new object());
}
}
lock (_dictionary[storedProcedureName])
{
return ExecuteStoredProcedure<TResult>(storedProcedureName, parameters);
}
}
public async Task<List<TResult>> ExecuteStoredProcedureWithLockAsync<TResult>(string storedProcedureName, object parameters, CancellationToken cancellationToken) where TResult : new()
{
lock (_dic)
{
if (_dic.ContainsKey(storedProcedureName) == false)
{
_dic.Add(storedProcedureName, new object());
}
}
List<TResult> result = new List<TResult>();
Monitor.Enter(_dic[storedProcedureName]);
try
{
result = await ExecuteStoredProcedureAsync<TResult>(storedProcedureName, parameters, cancellationToken);
}
finally
{
Monitor.Exit(_dic[storedProcedureName]);
}
return result;
}
答案 1 :(得分:3)
此代码适用于同步版本和异步版本
private static readonly SemaphoreLocker _semaphoreLocker = new SemaphoreLocker();
public async Task<List<TResult>> ExecuteStoredProcedureWithLockAsync<TResult>(string storedProcedureName, object parameters, CancellationToken cancellationToken) where TResult : new()
{
List<TResult> result = new List<TResult>();
await _semaphoreLocker.LockAsync(async () =>
{
result = await ExecuteStoredProcedureAsync<TResult>(storedProcedureName, parameters, cancellationToken);
}, cancellationToken);
return result;
}
private Object _locker = new Object();
public List<TResult> ExecuteStoredProcedureWithLock<TResult>(string storedProcedureName, object parameters) where TResult : new()
{
lock (_locker)
{
return ExecuteStoredProcedure<TResult>(storedProcedureName, parameters);
}
}
private class SemaphoreLocker
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public async Task LockAsync(Func<Task> worker, CancellationToken cancellationToken)
{
await _semaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
await worker();
}
finally
{
_semaphore.Release();
}
}
}
答案 2 :(得分:1)
如果所有用于调用存储过程的客户端仅调用ExecuteStoredProcedure
Web服务,则以下代码将正常工作:
private Object thisLock = new Object();
public List<TResult> ExecuteStoredProcedure<TResult>(string storedProcedureName, object parameters) where TResult : new()
{
lock (thisLock)
{
Type type = typeof(TResult);
StringBuilder sb = new StringBuilder();
sb.Append($"EXEC {storedProcedureName}");
if (parameters == null)
parameters = new { };
var properties = parameters.GetType().GetProperties();
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
sb.Append("@");
sb.Append(properties[i].Name);
sb.Append("=");
sb.Append("@p");
sb.Append(i);
if (i < properties.Length - 1)
{
sb.Append(",");
}
values[i] = properties[i].GetValue(parameters);
}
if (type == typeof(ActionModel) || type.BaseType == typeof(ActionModel))
{
sb.AppendLine("");
sb.AppendLine("WITH RESULT SETS ((IsValid BIT NULL,Id BIGINT NULL,Message NVARCHAR(MAX) NULL));");
}
return Database.SqlQuery<TResult>(sb.ToString(), values).ToList();
}
}