您经常需要生成随机字符串,例如用于登录 cookie 和唯一入口代码。
这些字符串总是需要存储在数据库中。因此,通过直接在数据库中生成随机字符串来让您的生活更简单。这是一个非常方便的 PostgreSQL 函数:
create function gen_random_bytes(int) returns bytea as '$libdir/pgcrypto', 'pg_random_bytes' language c strict; create function random_string(len int) returns text as $$ declare chars text[] = '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}'; result text = ''; i int = 0; rand bytea; begin -- generate secure random bytes and convert them to a string of chars. rand = gen_random_bytes($1); for i in 0..len-1 loop -- rand indexing is zero-based, chars is 1-based. result = result || chars[1 + (get_byte(rand, i) % array_length(chars, 1))]; end loop; return result; end; $$ language plpgsql;
给它一个数字:你想要的随机字符串的长度。它将返回该长度的随机字母数字文本。
select random_string(8); random_string ─────────────── yBuXga02 select random_string(8); random_string ─────────────── eP3X7yqe
随机冲突的机会非常小。但是您需要完全确定新的随机字符串是唯一的——在该表的该列中不存在。所以这里有一个函数,你可以给它字符串长度、表名和列名。它将返回一个确认为唯一的随机字符串——不存在于那里。它获取一个随机字符串,在该表和列中搜索它,如果找不到,则返回它。否则,如果找到,则获取一个新的随机字符串并循环返回,再次尝试直到找不到。
-- return random string confirmed to not exist in given tablename.colname create function unique_random(len int, _table text, _col text) returns text as $$ declare result text; numrows int; begin result = random_string(len); loop execute format('select 1 from %I where %I = %L', _table, _col, result); get diagnostics numrows = row_count; if numrows = 0 then return result; end if; result = random_string(len); end loop; end; $$ language plpgsql;
我曾经使用数据库触发器调用这样的函数,在任何插入时调用。但后来我发现了一些非常酷且简单得多的东西:您可以直接在表定义中将函数调用为默认值。
查看此表,调用 unique_random 作为其默认值:
create table things ( code char(8) primary key default unique_random(8, 'things', 'code'), name text );
如此简单明了!要使用它,您只需执行常规插入,它会生成保证唯一的默认值。
insert into things (name) values ('one') returning *; code │ name ──────────┼────── nRSXbVWQ │ one insert into things (name) values ('two') returning *; code │ name ──────────┼────── EAS9wGcl │ two
我发现这对于创建登录 cookie 特别方便:
create table cookies ( person_id int primary key, cookie char(32) unique default unique_random(32, 'cookies', 'cookie') );
与其让你的客户端代码、你的 JavaScript、Python、Ruby 或其他任何东西生成随机代码,不如直接将它放在你的数据库中,不仅因为它更干净,而且因为它节省了客户端代码之间的重复调用和数据库,确认唯一性。一个简单的 person_id 插入返回唯一且已保存的随机 cookie 字符串:
insert into cookies (person_id) values (1) returning *; person_id │ cookie ───────────┼────────────────────────────────── 1 │ 0P8Tp4wjXuTqCCh1NCR9XIom20z9IcYv
在/code/rand1.sql下载代码。