如何使用RDS Supabase后端BaaS能力:数据库函数(Database Function)

如何使用RDS Supabase后端BaaS能力:数据库函数(Database Function)

💡 原文中文,约13800字,阅读约需33分钟。
📝

内容提要

本文介绍 RDS Supabase 数据库函数:可用 SQL 或 PL/pgSQL 将聚合统计、跨表事务、流程控制等逻辑封装进数据库,弥补 Data API 仅支持单表 CRUD 的不足。函数支持 sql 与 plpgsql 语言,返回类型包括标量、SETOF、TABLE 和 trigger;SECURITY DEFINER 可绕过 RLS,但须通过 REVOKE/GRANT 收紧权限。可在 SQL Editor 或图形界面创建,前端通过 .rpc() 调用,触发器函数可自动刷新 updated_at、记录审计日志。

🔎

延伸解读

函数与Data API的分工:互补而非替代

文章明确数据库函数不替代Data API的CRUD,而是承接其覆盖不到的部分。单表读写仍用自动生成的接口,多表关联、聚合统计、跨表事务、流程控制才用函数封装。这种分工意味着开发者无需在应用层重复对齐字段,但也要注意:函数一旦创建,其逻辑变更需通过CREATE OR REPLACE并刷新schema缓存才能生效,迭代成本与直接改应用代码不同。

SECURITY DEFINER的权限收口是安全关键

文章强调SECURITY DEFINER函数默认授予PUBLIC执行权限,放在public模式下可被anon和authenticated调用,是公开的高权限入口。必须通过REVOKE FROM PUBLIC收回默认权限,再仅向authenticated授予EXECUTE。同时需配合SET search_path = public锁定搜索路径,防止同名对象劫持。若忽略收口,匿名用户可能借函数绕过RLS执行高权限操作,这是使用该模式时最需警惕的风险。

触发器函数的适用边界与注意事项

触发器函数专供触发器调用,不能经RPC;普通函数可经RPC但不能绑定为触发器。文章示例中,BEFORE触发器返回NEW使修改生效,返回NULL则取消该行操作;AFTER触发器用于审计,确保新值已落库。审计时用IS DISTINCT FROM安全比较含NULL的值。此外,为product_pricings绑定updated_at触发器前需先补列,说明触发器依赖目标表结构,迁移或新增表时要同步检查。

调用与维护中的实操细节

前端通过.rpc()调用函数,带参时用命名参数对象,键名对应参数名;返回集合的函数结果支持与表查询一致的链式过滤、排序、分页。创建或修改函数后须执行NOTIFY pgrst, 'reload schema'刷新缓存,首次可能延迟数秒,否则RPC无法识别。删除函数时须带参数类型以区分同名重载。这些细节虽小,但遗漏会导致调用失败或权限残留,建议纳入部署检查清单。

❓

Q&A

RDS Supabase 的数据库函数主要用来解决什么问题?

数据库函数用于封装 Data API 单表 CRUD 无法覆盖的逻辑,如聚合统计、跨表事务、流程控制、自动触发等。它不替代 CRUD,而是承接 CRUD 覆盖不到的部分,将业务逻辑下沉到数据库内完成,前端通过 .rpc() 调用即可获得结果。

数据库函数支持哪些语言和返回类型?

支持 sql 和 plpgsql 两种语言。sql 适合单条 SQL 查询,plpgsql 支持变量、分支、循环、异常处理等。返回类型包括 void、标量(如 bigint、numeric、text)、SETOF、TABLE(字段 类型, …) 以及 trigger(专供触发器调用)。

SECURITY DEFINER 函数有什么风险,如何安全使用?

SECURITY DEFINER 函数以函数属主权限执行,通常绕过 RLS,且默认授予 PUBLIC 执行权限,可能被 anon 或 authenticated 调用,成为高权限入口。安全使用需:设置 SET search_path = public 防止对象劫持;用 REVOKE ALL ON FUNCTION ... FROM PUBLIC 收回默认执行权;仅向 authenticated 等必要角色 GRANT EXECUTE;可在函数体内用 auth.uid() 校验调用者身份。

创建数据库函数有哪两种方式,分别适合什么场景?

有两种方式:1) SQL Editor 手写 CREATE FUNCTION 语句,适合任意复杂度,包括多步骤 PL/pgSQL、权限收口、触发器函数,语法完整可控;2) Database > Functions 图形表单创建,适合结构清晰的简单函数,可视化上手快,但复杂选项受限,权限收口仍需 SQL。简单函数可用图形界面,复杂逻辑推荐 SQL Editor。

前端如何调用数据库函数?支持过滤和分页吗?

前端通过 Supabase SDK 的 .rpc() 方法调用已暴露模式(如 public)下的函数。无参调用直接传函数名;带参调用第二参数为对象,键名对应参数名。返回集合的函数结果支持链式过滤、排序、分页,如 .eq()、.order()、.limit(),用法与表查询一致。

触发器函数如何实现字段自动维护和变更审计?

字段自动维护:定义返回 trigger 的函数,在 BEFORE UPDATE 触发器中用 NEW.updated_at = now() 并 RETURN NEW,绑定到目标表即可自动刷新更新时间。变更审计:建审计表,定义 AFTER UPDATE 触发器函数,用 IF NEW.price IS DISTINCT FROM OLD.price 判断变化后插入审计记录,确保新值已落库。

创建或修改函数后,为什么 RPC 调用不到?如何解决?

创建或修改函数后,需要刷新 PostgREST 的 schema 缓存,函数才对 RPC 可见。可执行 SQL:NOTIFY pgrst, 'reload schema'; 首次可能延迟数秒。

🏷️

标签

➡️

继续阅读