曾管理一万多台快递柜,优化了系统中生成唯一取件码的算法。

项目: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位,大多数人看一次默念一下,即可完成输入!