您的位置:首页 > 其它

.NET:可扩展的单据编号生成器 之 基于缓冲区的顺序号

2013-05-14 08:39 323 查看

背景

我在上篇文章“.NET:可扩展的单据编号生成器 之 顺序号(防止重复)”中介绍了如何使用“种子表”和“悲观锁”解决顺序号的问题。昨天找朋友讨论,说这种速度不够高,今天就稍微改进一下,引入一个内存缓冲区,提高生成的速度。

思路

引入内存缓冲区后,顺序号的生产流程变为:在内存中维护一个顺序号区间,在这个区间内,就直接查内存,否则更新种子表并重新更新内存区间。还是直接看代码吧。

实现

代码下载:http://yunpan.cn/Q5jj5yedRAtk5

SeedCodeRuleProvider.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Transactions;
using System.Text.RegularExpressions;
using System.Data.Entity.Infrastructure;

namespace EntityCodeRuleDemo
{
public class SeedCodeRuleProvider : ICodeRuleProvider
{
private static readonly int _OnceBufferSize = 10000;
private static readonly Dictionary<string, BufferSeed> _Buffer = new Dictionary<string, BufferSeed>();

private readonly int _width;

public SeedCodeRuleProvider(int width)
{
_width = width;
}

public string Generate(object entity)
{
return GetSeedValue(entity).ToString().PadLeft(_width, '0');
}

protected virtual string GetKey(object entity)
{
return entity.GetType().FullName;
}

private int GetSeedValue(object entity)
{
var key = this.GetKey(entity);

lock (_Buffer)
{
if (!_Buffer.ContainsKey(key))
{
this.SetBufferSeed(entity, key);
}
}

lock (_Buffer[key])
{
if (_Buffer[key].IsOverflow())
{
this.SetBufferSeed(entity, key);
}

_Buffer[key].CurrentValue++;

return _Buffer[key].CurrentValue;
}
}

private void SetBufferSeed(object entity, string key)
{
var value = this.GetOrSetSeedValueFormDatabase(entity);

_Buffer[key] = new BufferSeed
{
CurrentValue = value - _OnceBufferSize,
MaxValue = value
};
}

private int GetOrSetSeedValueFormDatabase(object entity)
{
var key = this.GetKey(entity);

try
{
using (var ts = new TransactionScope(TransactionScopeOption.RequiresNew,
new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
{
var value = 0;

using (var context = new TestContext())
{
var seed = context.CodeSeeds.Where(x => x.Key == key).FirstOrDefault();
if (seed == null)
{
seed = new CodeSeed { Id = Guid.NewGuid(), Key = key, Value = -1 };
context.CodeSeeds.Add(seed);
}

seed.Value += _OnceBufferSize;
context.SaveChanges();

value = seed.Value;
}

ts.Complete();

return value;
}
}
catch (DbUpdateException)
{
return this.GetSeedValue(entity);
}
}

public static SeedCodeRuleProvider SeedCodeRuleProviderFactory(string literal)
{
var match = new Regex("^<种子(:(?<宽度>.*?))?>$").Match(literal);

var width = match.Groups["宽度"].Value;

return new SeedCodeRuleProvider(string.IsNullOrEmpty(width) ? 5 : int.Parse(width));
}

private class BufferSeed
{
public int CurrentValue { get; set; }

public int MaxValue { get; set; }

public bool IsOverflow()
{
return this.CurrentValue >= this.MaxValue;
}
}
}
}


Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Diagnostics;
using System.Text.RegularExpressions;

namespace EntityCodeRuleDemo
{
class Program
{
static void Main(string[] args)
{
CodeRuleInterpreter.RegistProviderFactory(new Regex("^<种子(:(?<宽度>.*?))?>$"), SeedCodeRuleProvider.SeedCodeRuleProviderFactory);

var generator = CodeRuleInterpreter
.Interpret("前缀_<日期:yyyy_MM_dd>_<属性:NamePinYin>_<种子:6>");

var watch = Stopwatch.StartNew();

for (var i = 0; i < 10000; i++)
{
generator.Generate(new Employee { NamePinYin = "DUANGW" });
}

watch.Stop();

Console.WriteLine("1万条编号用时:" + watch.Elapsed);
}
}
}


执行结果



备注

优化前后,速度相差几百倍。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: