【问题标题】:What would be a good order id scheme for a e-commerce solution or paid web service?对于电子商务解决方案或付费网络服务,什么是好的订单 ID 方案?
【发布时间】:2010-10-31 04:33:26
【问题描述】:

考虑以下几点:

a) 您需要保密(例如不告诉所有人您收到了多少订单)。

c) 您必须考虑时间,以便消费者可以对订单的顺序进行排序。

d) 应该全部是数字还是十六进制等?

e) 您的消费者可以通过电话向支持团队说的内容,足以识别订单,而无需工作人员出于安全考虑而要求提供电子邮件等。

我很想听听一些意见。

PS:任何为解决这个问题而设计的算法对我来说也都是有效的答案。

【问题讨论】:

  • “为解决这个问题而设计的一段 PHP 或 MySQL 代码对我来说是一个有效的答案”——这是“请发送代码”的另一种说法吗?
  • 不,但是如果有人提出了一种算法,可以很好地解决这个问题,我会很喜欢。我已经编辑了文本以避免其他人误解我的意图。

标签: database-design e-commerce uniqueidentifier


【解决方案1】:

这是我的解决方案。

有一个 x-y-z 三个部分,其中 x 是时间戳,y 是随机码,z 是 x 和 y 连接产生的校验位。但为了简化(使其更小),x 和 y 以自定义基数给出,而不是数字基数 10,但 z 仍以 10 为基数给出。

您可以通过这种方法获得的 ID 示例:

  • LP9NTX-8D41-QW6R-9
  • LP9NTY-5H3L-BFS7-5
  • LP9NTZ-RWL3-D619-8
  • LP9NVB-BW74-788W-6
  • LP9NVW-G17D-4911-8

因此您可以按时间戳排序(如果您不确切知道数字基数是什么,请注意它是如何按“递增字母数字”顺序排列的)。

为此,我使用了base58 的数字+大写字母(最后我使用小写还是大写都没有关系),它是base62,没有一些令人困惑的字符。 Flickr, bit.ly and others use base58 for making Twitter 'friendly' links and the like.

下面的 Verhoeff::calcsum 是 Verhoeff’s Dihedral Group D5 Check by Dahnielson. 我所做的唯一编辑是将他的代码放在一个类中,所以它是一样的。

这是一些代码:(*与我在上面的行中承诺的有所修改^)

<?php
    $time_divisor = 3;
    $base = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";//consider using another base **see note below**
    $lower_limit = 50000;//just to avoiding to confuse the user with a lower number
    $upper_limit = 1291467968;//1291467968 == ZZZZZZ in this base I used
    //you can check the limit with base_decode("ZZZZZZ", $base);
    $ptime = (int)($_SERVER['REQUEST_TIME']/$time_divisor);//or time();
    $rand1 = mt_rand($lower_limit, $upper_limi);
    $rand2 = mt_rand($lower_limit, $upper_limi);
    $ptime_b = base_encode($time, $base);
    $rand1_b = base_encode($rand1, $base);
    $rand2_b = base_encode($rand2, $base);

    $order_id = $ptime_b.$rand1_b.$rand2_b.Verhoeff::calcsum($time.$rand1.$rand2);
    echo $order_id;
?>

就在我写完这篇文章之后,我想到了另一个可能出错的事情。我记得你不希望你的消费者感到被侮辱。因此,即使认为诸如“f?ck”或“4ss”之类的坏词最终可能会出现(而且几乎肯定会出现),明确的词(例如将前一个词中的“4”更改为“a”)绝对不是.因此,我建议您改用以下备用 base/upper_limit:

<?php
    $lower_limit = 27000;//=2111
    $upper_limit = 809999;//=ZZZZ
    $base = "123456789BCDFGHJKLMNPQRSTVWXYZ";//erased -a -e -u
?>

请注意,如果您尝试使用更大的数字,您将达到 PHP 的 int 上限以及 mt_rand 限制,这可以通过 mt_getrandmax() 看到。另外,我想说的是,就我所见,mt_rand 的熵就足够了。

如果您需要更大的随机部分数字,我建议您仅在其中附加第三部分,例如 mt_rand(i, j);其中 i 和 j 是您的基数的最小值和最大值,它将以 $num-chars 长度增加您的订单 ID(实际上是我做了这个,使用上面的配置)。

在数据库方面,它是一个独特的字段,可以避免冲突。

谢谢大家。

【讨论】:

    【解决方案2】:

    你认为合适的任意长度的随机字符串怎么样?使用不易与其他字符混淆的字符用于通过电话阅读。所以在每个订单上调用类似:

        public static string GetRandomString(int length)
        {
            char[] chars = "ACDEFGHJKMNPQRTWXY34679".ToCharArray();
            var crypto = new RNGCryptoServiceProvider();
            var data = new byte[length];
            crypto.GetNonZeroBytes(data);
            var result = new StringBuilder(length);
            for (int i = 0; i < data.Length; i++)
            {
                result.Append(chars[data[i] % chars.Length]);
            }
    
            return result.ToString();
        }
    

    猜测从上述方法返回的 8 个字符是 1/282429536481 的机会。而且您将通过唯一约束在数据库中保持完整性,对吗?

    【讨论】:

    • “排序顺序”呢?
    【解决方案3】:

    java.util.UUID.randomUUID()

    【讨论】:

      【解决方案4】:

      您可以使用GUID。要将其缩小为对客户友好的字符串,值得通过 Base32 转换器运行该值,这将产生一个包含 26 个字符的 A-Z 和数字 2-7 的字符串

      为了满足您的其他条件,您可以在 guid 值上附加一个校验位,并且您可能需要在数据库中单独使用一个真正的增量订单号来保证唯一性并允许自然索引/排序。

      【讨论】:

      • 您只需要 GUID 的前几个字符就可以真正缩小实际条目的范围,看看 Git 如何只需要前 4-5 个字符来唯一标识一个提交。您只需向客户询问更多字符,直到您与他们的名字匹配。
      猜你喜欢
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多