dbms_random.value不接受参数,生成[0,1)浮点数;需手动换算得[a,b)区间;整数需round/floor但注意边界;random返回带符号整数,避免abs而用mod;string类型码仅限'u','l','a','x','p';高并发下需显式seed确保随机性。
dbms_random.value 生成浮点随机数,但默认范围是 0 到 1(不含 1)
很多人以为 DBMS_RANDOM.VALUE 能直接生成指定区间的数,结果写成 DBMS_RANDOM.VALUE(1, 100) —— 这会报错:ORA-06553: PLS-306: wrong number or types of arguments。它根本不接受参数。
要生成 [a, b) 区间的浮点数,得手动换算:
-
DBMS_RANDOM.VALUE返回的是NUMBER类型,值域为 [0, 1) - 比如要 [10, 50),写成
10 + (50 - 10) * DBMS_RANDOM.VALUE - 注意:结果可能带多位小数,如需整数,必须显式
ROUND或FLOOR,但要注意边界——FLOOR(10 + 40 * DBMS_RANDOM.VALUE)得到的是 [10, 49],不是 [10, 50]
DBMS_RANDOM.RANDOM 返回带符号整数,别直接当正数用
DBMS_RANDOM.RANDOM 返回的是 PLS_INTEGER,范围约在 [-2^31, 2^31) 之间,不是 0 开始的正整数。
常见误用:想取一个正 ID 就直接写 ABS(DBMS_RANDOM.RANDOM) —— 这会导致 0 出现概率翻倍(因为 RANDOM 可能返回 0,而 ABS(-0) 还是 0),且负数取绝对值后分布不再均匀(边界值被折叠)。
- 安全做法:用
MOD(DBMS_RANDOM.RANDOM, N) + 1生成 [1, N] 的均匀整数 - 如果 N 很大(接近 2^31),
MOD仍安全;但避免用ABS做归一化 -
DBMS_RANDOM.RANDOM比VALUE稍快,适合对性能敏感的批量场景
DBMS_RANDOM.STRING 生成随机字符串时,类型参数不能写错
DBMS_RANDOM.STRING 第二个参数是单字符类型码,不是字符串描述。写成 'ALPHANUMERIC' 或 'upper' 全都会报 ORA-06502: PL/SQL: numeric or value error。
合法值只有 5 种单字母代码,区分大小写:
-
'u':大写字母(A–Z) -
'l':小写字母(a–z) -
'a':大小写字母混合(A–Z, a–z) -
'x':大写字母 + 数字(A–Z, 0–9) -
'p':所有可打印 ASCII 字符(含标点,慎用——可能产生 SQL 注入风险字符如'、;)
例如生成 8 位大写字母+数字的 token:DBMS_RANDOM.STRING('x', 8)
DBMS_RANDOM 初始化不是必须的,但并发场景下不初始化可能出问题
Oracle 官方文档说“首次调用任意函数时自动初始化”,听起来很省心。但在高并发短连接环境(比如 Web 应用频繁新建 session),多个会话几乎同时首次调用 DBMS_RANDOM.VALUE,可能因共享种子导致生成重复序列。
这不是 bug,是伪随机数生成器的固有行为:没显式设种子时,Oracle 用当前时间+进程 ID 初始化,精度有限。
- 关键点:如果需要强随机性(如生成密码重置 Token),务必先调用
DBMS_RANDOM.SEED(SYSDATE || USER || DBMS_UTILITY.GET_TIME) -
SEED接受NUMBER或VARCHAR2;用SYSDATE单独做 seed 不够,毫秒级相同就撞车 - 不需要每次调用前都
SEED,一次初始化足够;但不要在包初始化块里静态SEED,否则所有会话共用同一序列
真正难的不是记函数怎么写,而是想清楚你要的是“看起来随机”还是“难以预测”——前者用默认就行,后者必须自己控 seed,而且得确保 seed 本身不可被推测。










