我正在尝试生成优惠码以提供折扣。我试过了,Math.Random()
但我不确定它是否每次都能保证一个唯一的代码?
我也尝试过使用dbms_random.string
“Oracle”的实用程序来生成随机数,但它也不能保证唯一的代码。
有谁知道一个好的算法来做到这一点?
我正在使用 java 和 oracle 来开发代码。
编辑:看了几个回复后,我想补充一点,我必须将每个生成的代码存储在表中。并且生成的代码应该是字母数字的。
您可以使用 Java UUID 类。它生成随机的 128 位字母数字字符串。一个字符串重复的可能性是天文数字的低。
具体来说:
import java.util.UUID
.
.
String uniqueString = UUID.randomUUID().toString()
.
.
从 10g 开始的 Oracle 包含 dbms_crypto 包以允许生成真正的随机序列。
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_crypto.htm#i1000605。
在获得一些随机的 RAW 字节后,可以使用 utl_encode 包将这些字节编码为合适的字母数字字符串。
http://psoug.org/reference/utl_encode.html
如果优惠券代码足够长,冲突应该是不可行的,但您仍然可以将优惠券创建包装在 PL/SQL 函数中以处理任何冲突。例如。如果 INSERT 失败,请使用 UNIQUE 约束并捕获异常。(正如鲍勃贾维斯所建议的那样。)
随机是随机的,但您正确识别这并不意味着唯一。
您需要将已使用的代码存储在某个地方(例如回到数据库中),然后在创建新代码时扫描记录。
实际上,您可能希望预先生成 100(或 1000 或 10,000)张优惠券,存储它们,并根据需要分配它们。
我会结合随机数+序列号。这为您提供了一个唯一的随机数,因为序列号是唯一的。
否则,您需要进行反复试验。也许提前节省运行时间。假设您有一个带有唯一索引 coupon_id 的表“coupon-keys”。您生成随机密钥,然后将其插入。如果不是唯一的,您会捕获插入失败并重试,直到生成足够的优惠券密钥。此外,您还有一个“已使用”列,每次您发放优惠券时,您都会更新该列以跟踪仍然可用的优惠券号码。
创建一个字母数字字符数组,代表您的优惠券代码的所有有效字符。假设它都是大写和小写字母字符。
String chars[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
您可以将任何整数转换为更短的代码,基本上是通过执行数字基数转换(尽管顺序相反)。
int max=100000000;
int random=(int) (Math.random()*max);
StringBuffer sb=new StringBuffer();
while (random>0) {
sb.append(chars[random % chars.length]);
random /= chars.length;
}
String couponCode=sb.toString();
因此,生成一个随机数,将其缩短为字符串,然后将其插入数据库。如果插入因碰撞而失败,则重试。碰撞应该是相当罕见的,并且在它们发生时只会产生最小的成本。您的优惠券代码应保持简短且易于输入。
以下是我的建议:
你的桌子应该看起来像
CREATE TABLE COUPONS
(COUPON_CODE NUMBER
CONSTRAINT PK_COUPONS
PRIMARY KEY
USING INDEX); -- plus whatever other fields you need
您生成唯一代码的代码应该类似于
DECLARE
nCoupon_code NUMBER;
bCode_unique BOOLEAN;
BEGIN
bCode_unique := FALSE;
WHILE bCode_unique = FALSE LOOP
BEGIN
nCoupon_code := GENERATE_COUPON_CODE; -- function to generate a coupon code
INSERT INTO COUPONS (COUPON_CODE)
VALUES (nCoupon_code);
bCode_unique := TRUE;
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
NULL; -- Fall through, loop back to the top, generate new code, continue
END;
END LOOP; -- bCode_unique
END;
这里发生的事情是程序首先将“代码唯一”标志设置为 FALSE,表示尚未生成唯一代码。然后进入一个循环,只要“代码唯一”标志仍然为 FALSE,就会继续。然后生成优惠券代码并将其存储到数据库中。如果代码是唯一的,一切都会很好,“代码唯一”标志将被设置,并且循环将被退出。但是,如果代码不是唯一的,则 INSERT 语句将失败并出现 DUP_VAL_ON_INDEX 异常。这是因为 COUPON_CODE 是 COUPONS 表上的主键,并且我们知道主键具有三个属性:它必须是非 NULL,如果不能更改,它必须是唯一的。(出于我们的目的,我们可以对 COUPONS.COUPON_CODE 使用 UNIQUE 约束并获得相同的效果)。如果由于生成的优惠券代码不唯一而引发 DUP_VAL_ON_INDEX 异常,则将输入异常处理程序,代码将完全不执行任何操作;也就是说,“代码唯一”标志将保持为 FALSE,代码将从异常处理程序中退出,并且由于“代码唯一”标志仍然为 FALSE,循环将重新开始,生成另一个代码,等等,等等,等等,直到最终生成唯一代码并且 INSERT 成功。
这可能看起来需要做很多工作,但如果优惠券代码生成算法选择得当,它就不会产生很多冲突,因此不必过于频繁地循环。IMO 考虑到环境,这是一个合理的解决方案 - 在 PL/SQL 中,您指望使用数据库来完成一些繁重的工作,例如保证唯一性。您可以花费大量时间尝试提出一种永远不会、永远可能生成重复项的真正代码生成算法,或者您可以提出一些即使不完美也很好的东西并与数据库一起工作以确保最终选择的代码是唯一的。YMMV。实现一个真正的算法可能会很有趣,如果不是特别好地利用时间的话。:-)
分享和享受。