必要になる前に、一連のid値(データベースID値など)をフェッチするための最良の方法に関するアドバイスを見つけたいと思っています。一意のID(int)を必要とするクラスがいくつかあります。実行したいのは、次に使用可能なID(クラスごと、サーバーごと)をフェッチし、ローカルでキャッシュできるようにすることです。IDを取得したら、次のIDを準備したいなど。
私がやろうとしていることを示すために、いくつかのコードを作成しました。コードはひどいです(ロックなどが含まれている必要があります)が、私はそれがポイントを理解していると思います。奇数IDを失うことは問題ではありません-重複IDは(問題)です。GetNextIdAsyncの根性に満足しています-procを呼び出します
this.Database.SqlQuery<int>("EXEC EntityNextIdentityValue @Key",
new SqlParameter("Key", key))).First();
sp_getapplockを使用して各戻り値が一意(および増分)であることを確認するSQLServerの場合。
static class ClassId
{
static private Dictionary<string, int> _ids = new Dictionary<string,int>();
static private Dictionary<string, Thread> _threads = new Dictionary<string,Thread>();
static ClassId()
{
//get the first NextId for all known classes
StartGetNextId("Class1");
StartGetNextId("Class2");
StartGetNextId("Class3");
}
static public int NextId(string key)
{
//wait for a current call for nextId to finish
while (_threads.ContainsKey(key)) { }
//get the current nextId
int nextId = _ids[key];
//start the call for the next nextId
StartGetNextId(key);
//return the current nextId
return nextId;
}
static private void StartGetNextId(string key)
{
_threads.Add(key, new Thread(() => GetNextIdAsync(key)));
_threads[key].Start();
}
static private void GetNextIdAsync(string key)
{
//call the long running task to get the next available value
Thread.Sleep(1000);
if (_ids.ContainsKey(key)) _ids[key] += 1;
else _ids.Add(key, 1);
_threads.Remove(key);
}
}
私の質問は、必要になる前に必要になる次の値を常に持つための最良の方法は何ですか?クラスはどのように配置する必要があり、ロックはどこに配置する必要がありますか?たとえば、GetNextIdAsync()内のロックは新しいスレッドを追加しますが、それを開始せず、StartGetNextId()を.Start()を呼び出すように変更しますか?