C#事务-最佳性能
本文关键字:性能 最佳 事务 | 更新日期: 2023-09-27 18:10:12
我的Web应用程序有一个类WorkItem
,其中包含一个RecordID
(Guid作为主键(和一个由Type-Date-RandomNumbers
组成的FriendlyID
(字符串(。
如果我创建了一个新的WorkItem,我也会创建一个新FriendlyID
FriendlyID的格式不能更改(客户端规范(,与<Type (one char)>-<Current Date (yyymmdd)>-<6 random numbers>
类似。
private string GenerateFriendlyID()
{
string res = String.Empty;
// code omited
// ...
// IT'S NOT THE QUESTION HOW TO PROGRAM THIS METHOD!
// It's about the fastest and best way/design to make
// sure the generated ID is unique! (see below)
return res; // sth like "K-20110930-158349"
}
public override void Create()
{
if (String.IsNullOrEmpty(friendlyID))
{
GenerateFriendlyID();
}
base.Create();
}
这段代码在重负载下确实会失败,所以我多次获得相同的FriendlyID
确保我的友好ID唯一的最佳方法是什么
- 在数据库中对FriendlyID进行UNIQUE约束
- 开始事务,生成FriendlyID,插入并提交
- 如果出现SQLException,请回滚并重试
- 只要创建它。
- 使用
this.FriendlyID
选择所有工作项 - 如果选择是
> 1
,则重复此操作,直到它是== 1
- 使用
我相信还有另一种方法,但我想#1应该是首选。
有没有我错过的路,或者#1是我要走的路?我不喜欢在我的工作流程中使用异常,我知道它们真的很慢。
我的建议是,在任何情况下,无论你想生成什么类型的id,都要在SQL中的存储过程中执行,而不是从中执行。NET客户端代码。最好有一个原子入口点,它接受一些参数并完成任务,这样你就可以调用存储的,保存你的记录,并将id作为out参数返回给你,甚至不止一个,比如唯一的代码和guid。
然后,通过这种方式,您可以将并发问题从中移除。NET客户端代码到数据库服务器和数据库服务器是设计的,以很好地处理并发。
由于RecordID
已经基于GUID,我会解析它来创建友好的ID。Guid.ToByteArray()
可能是一个有用的起点。
使用M.Fowler的PoEAA中的KeyGenerator模式。这是一个文件系统解决方案的示例,它使用互斥来进行跨进程锁定。在MS SQL的情况下,您可以使用事务而不是互斥。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Runtime.CompilerServices;
namespace ConsoleApplication1
{
public class KeyGenerator
{
private string FileName;
private long IncrementedBy;
private long NextId;
private long MaxId;
public KeyGenerator(string filename, long incrementedby)
{
FileName = filename;
IncrementedBy = incrementedby;
NextId = MaxId = 0;
}
//[MethodImpl(MethodImplOptions.Synchronized)]
public long NextID()
{
if (NextId == MaxId)
{
reserveIds();
}
return NextId++;
}
private void reserveIds()
{
Mutex m = new Mutex(false, "Mutex " + FileName.Replace(Path.DirectorySeparatorChar, '_'));
try
{
m.WaitOne();
string s = File.ReadAllText(FileName);
long newNextId = long.Parse(s);
long newMaxId = newNextId + IncrementedBy;
File.WriteAllText(FileName, newMaxId.ToString());
NextId = newNextId;
MaxId = newMaxId;
// Simulate some work.
Thread.Sleep(500);
}
finally
{
m.ReleaseMutex();
}
}
}
}