Derek Sivers blog 09月29日 12:01
PostgreSQL函数简化随机字符串生成与唯一性保障
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了如何利用PostgreSQL的自定义函数来简化随机字符串的生成过程,特别适用于需要生成登录Cookie和唯一入口代码的场景。文中提供了`gen_random_bytes`和`random_string`函数,用于生成指定长度的随机字节串和文本字符串。更重要的是,介绍了一个名为`unique_random`的函数,该函数能够生成在指定表和列中保证唯一性的随机字符串,有效避免了重复。最后,展示了如何将`unique_random`函数作为表的默认值,实现更简洁高效的数据库设计。

💡 **便捷的随机字符串生成**: PostgreSQL提供了`gen_random_bytes`和`random_string`函数,可以轻松生成指定长度的随机字节串和包含数字、大小写字母的文本字符串,满足日常开发中对随机字符串的需求。

🔒 **确保唯一性的`unique_random`函数**: 为了解决随机字符串可能存在的重复问题,`unique_random`函数通过循环查询数据库来确保生成的字符串在特定表和列中是唯一的,极大地提高了数据生成的可靠性。

🚀 **函数作为默认值的优雅设计**: 将`unique_random`函数直接作为表的列默认值,可以在插入数据时自动生成唯一随机码,无需在应用程序层面进行额外的逻辑处理,简化了数据库结构和开发流程,尤其适用于生成主键或唯一标识符。

🔌 **简化客户端与数据库交互**: 通过在数据库层面处理随机字符串的生成和唯一性校验,可以减少客户端代码与数据库之间的通信次数,提高效率,并使代码更加集中和易于维护,例如在生成登录Cookie时尤为方便。

You often need to generate random strings, like for login cookies and unique entry codes.

These strings always need to be stored in the database.So make your life simpler by generating the random strings directly in the database.Here's a very handy PostgreSQL function to do it:

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;
download code

Give it a number: the length of the random string you want.It will return random alphanumeric text of that length.

select random_string(8);random_string ─────────────── yBuXga02select random_string(8); random_string ─────────────── eP3X7yqe
download code

The chance of random clash is very small.But you need to be completely sure that the new random string is unique — not already existing in that column in that table.So here's a function where you give it the string length, table name, and column name.It will return a random string confirmed to be unique — to not exist there already.It gets a random string, searches for it in that table and column, and if not found, returns it.Otherwise, if it is found, gets a new random string and loops back, trying again until not found.

-- return random string confirmed to not exist in given tablename.colnamecreate 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;
download code

I used to call functions like this using database triggers, called on any insert.But then I found out something surprisingly cool and so much simpler:You can call functions as default values directly in table definitions.

Look at this table, calling unique_random as its default value:

create table things (  code char(8) primary key default unique_random(8, 'things', 'code'),  name text);
download code

So simple and clear!To use it, you just do a regular insert, and it generates the guaranteed-unique default value.

insert into things (name) values ('one') returning *;   code   │ name ──────────┼────── nRSXbVWQ │ oneinsert into things (name) values ('two') returning *;   code   │ name ──────────┼────── EAS9wGcl │ two
download code

I've found this particularly handy for creating login cookies:

create table cookies (  person_id int primary key,  cookie char(32) unique default unique_random(32, 'cookies', 'cookie'));
download code

Instead of having your client code, your JavaScript, Python, Ruby or whatever, generating the random code, it's extra-nice to have this in your database directly, not only because it's cleaner, but because it saves repeated calls between your client code and database, confirming uniqueness.One simple insert of the person_id returns the unique and already-saved random cookie string:

insert into cookies (person_id) values (1) returning *; person_id │              cookie              ───────────┼──────────────────────────────────         1 │ 0P8Tp4wjXuTqCCh1NCR9XIom20z9IcYv
download code

Download the code at /code/rand1.sql.

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

PostgreSQL 数据库 随机字符串 函数 唯一性 默认值 登录Cookie PostgreSQL Database Random Strings Functions Uniqueness Default Values Login Cookies
相关文章