曾管理一万多台快递柜,优化了系统中生成唯一取件码的算法。
项目:https://github.com/nnhy/PickupCode
新建项目,添加 Nuget 应用 NewLife.Redis ,借助其Add去重能力。
代码如下:
private static void Main(string[] args) { XTrace.UseConsole(); var redis = new FullRedis("127.0.0.1", null, 3); var stationCode = "2743"; for (int i = 0; i < 8; i++) { var code = BuildPickupCode(redis, stationCode); XTrace.WriteLine("取件码{0}:{1}", i + 1, code); } } /// <summary>为站点生成唯一取件码</summary> /// <param name="cache">redis确保48小时不重复</param> /// <param name="stationCode">站点编码</param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="Exception"></exception> static string BuildPickupCode(ICache cache, string stationCode) { if (stationCode.IsNullOrEmpty()) throw new ArgumentNullException(nameof(stationCode)); var rnd = new Random(); for (int i = 0; i < 10; i++) { // 生成6位随机数作为取件码,不足6位时前面补0 var code = rnd.Next(100000, 1000000).ToString().PadLeft(6, '0'); // 站点结合取件码作为唯一key,Redis去重确保48小时内不重复。如果重复再生成一次新的随机数 var key = $"{stationCode}:{code}"; if (cache.Add(key, code, 48 * 3600)) return code; } // 连续10次都失败,就有可能是redis网络或代理有问题了 throw new Exception("Build PickupCode Error!"); }
运行效果
原理比较简单,借助Redis的SETNX能力,当key不存在时添加,已存在时不改变已有值。
SETNX的返回值0和1表示是否添加成功。
在NewLife.Redis中redis.Add即是SETNX的封装,如果添加成功,说明这个随机取件码可用,反之则生成新的随机取件码。
Add第二个参数意义不大,第三个参数表示有效期,这里使用48小时。也就是说,这个key在48小时后将会自动消失,该取件码将有可能重新生成用于新的快递。实际运营中,这个有效时间也可能是5到7天。
最后吐槽一下,很多快递柜的8位取件码,实在不利于快速记忆,不利于便捷输入。如果使用6位,大多数人看一次默念一下,即可完成输入!