正如文章《通用的業務編號規則設計實現(附源碼)》 文章里需要一個多實例和線程安全的序列化生成器,在SQL Server 2012+ 版本 有一個通過.NET程式集的序列號transact-sql 函數 http://msdn.microsoft.com/zh-cn/library/ff878091.
正如文章《通用的業務編號規則設計實現(附源碼)》 文章里需要一個多實例和線程安全的序列化生成器,在SQL Server 2012+ 版本 有一個通過.NET程式集的序列號transact-sql 函數 http://msdn.microsoft.com/zh-cn/library/ff878091.aspx。 這篇文章向大家介紹一個使用SQL Server 和Sql Azure 以及Mongodb 實現的序列號生成器。
在Github上有個項目 https://github.com/getAddress/Sequence ,我Fork了一份,增加了一個Mongodb 實現,地址是https://github.com/geffzhang/Sequence。下麵我介紹下使用Mongodb實現的sequence 存儲,主要就是實現介面IstateStore。
這裡實現的關鍵點就是在更新數據的時候如何保證原子性的操作,Mongo 可以使用findAndModify命令, findAndModify可以從資料庫查找返回一個文檔的同時更新/插入/刪除文檔,原子操作,線程安全,功能強大,原型複雜。
public async Task<bool> UpdateAsync(SequenceKey sequenceKey, ISequence sequence)
{
var sequenceEntity = sequence as Sequences;
sequenceEntity.Id = sequenceKey.Value;
var query = Query.And(Query.EQ("_id", ObjectId.Parse(sequenceKey.Value)));
var update = MongoDB.Driver.Builders.Update < Sequences>.Set( c => c.CurrentValue , sequenceEntity.CurrentValue);
var updatedSequenceEntity = this.Collection.FindAndModify(new FindAndModifyArgs() { Query = query, Update = update, VersionReturned = FindAndModifyDocumentVersion.Original, SortBy = null });
var doc = updatedSequenceEntity.ModifiedDocument;
return doc != null;
}
findAndModify命令中每個鍵對應的值如下所示。
findAndModify 字元竄,集合名。
query 查詢文檔,用來檢索文檔的條件。
sort 排序結果的條件。
update 修改器文檔,對所找到的文檔執行的更新。
remove 布爾類型,表示是否刪除文檔。
new 布爾類型,表示返回的是更新前的文檔還是更新後的文檔。預設是更新前的文檔。
"update"和"remove"必須有一個,也只能有一個。要是匹配不到文檔,這個命令會返回一個錯誤。
這個命令有些限制。它一次只能處理一個文檔,也不能執行upsert操作,只能更新已有文檔。
相比普通更新來說,findAndModify速度要慢一些。大概耗時相當於一次查找,一次更新和一次getLastError順序執行所需的時間。
使用起來非常簡單,下麵我們使用Mongodb 作為代碼示例:
通過Nuget 安裝getAddress.Sequence.Mongo:
- 根據業務需求創建一個序列化生成器,也就是SequenceKey ,Mongo 使用它的ObjectId 來作為Key
var stateProvider = GetStateProvider();
var sequenceGenerator = new SequenceGenerator(stateProvider);
var sequence = await CreateSequence(stateProvider,increment: 0, startAt: 5);
var sequenceKey = await stateProvider.AddAsync(sequence);
- 使用這個SequenceKey 就可以用調用了
var stateProvider = GetStateProvider();
var sequenceGenerator = new SequenceGenerator(stateProvider);
var nextValue1 = await sequenceGenerator.NextAsync(new SequenceKey { Value = "56af206c7c2a5827389ad412"});
項目里有完整的單元測試用例,跑完整個單元測試用例,Mongodb的數據展示一下:
我們把數據存儲在一個叫做Sequences的Collection里,_id 列就是我們的sequenceKey。StartAt 表示起點, Increment 表示步長, MaxValue 表示最大值, MinValue 表示最小值,Cycle 表示達到最大值,從頭開始迴圈,CurrentValue 表示當前值。