实时

订阅数据库变更

从您的网站或应用程序实时监听数据库变更


您可以使用 Supabase 订阅实时数据库变更。目前提供两种方案:

  1. 广播模式 - 推荐方案,具备更好的扩展性和安全性
  2. Postgres变更监听 - 更简单的方案,配置较少,但扩展性不如广播模式

使用广播模式

要在记录创建、更新或删除时自动发送消息,我们可以为任意表附加 Postgres触发器。Supabase Realtime 提供了 realtime.broadcast_changes() 函数,可与触发器配合使用。该函数会使用私有频道,且需要满足广播授权的行级安全策略(RLS)。

广播授权

接收广播消息需要配置实时授权。以下是允许认证用户监听主题消息的策略示例:

1
2
3
4
5
create policy "认证用户可接收广播消息"on "realtime"."messages"for selectto authenticatedusing ( true );

创建触发器函数

让我们创建一个函数,可以在记录创建、更新或删除时调用。该函数将利用Postgres原生的触发器变量。在这个示例中,我们希望有一个名为topic:<记录ID>的主题,用于广播事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
create or replace function public.your_table_changes()returns triggersecurity definerlanguage plpgsqlas $$begin perform realtime.broadcast_changes( 'topic:' || coalesce(NEW.topic, OLD.topic) ::text, -- 主题 - 我们要广播的目标主题 TG_OP, -- 事件 - 触发函数的事件类型 TG_OP, -- 操作 - 触发函数的操作类型 TG_TABLE_NAME, -- 表名 - 触发器的来源表 TG_TABLE_SCHEMA, -- 模式 - 来源表的所属模式 NEW, -- 新记录 - 变更后的记录 OLD -- 旧记录 - 变更前的记录 ); return null;end;$$;

创建触发器

让我们设置一个触发器,使得在对表进行任何更改后执行该函数。

1
2
3
4
5
create trigger handle_your_table_changesafter insert or update or deleteon public.your_tablefor each rowexecute function your_table_changes ();

客户端监听

最后,在客户端监听 topic:<record_id> 主题来接收事件。请记住将频道设置为私有频道,因为 realtime.broadcast_changes 使用了 Realtime 授权机制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { createClient } from '@supabase/supabase-js'const supabase = createClient('your_project_url', 'your_supabase_api_key')// ---cut---const gameId = 'id'await supabase.realtime.setAuth() // 需要设置 Realtime 授权const changes = supabase .channel(`topic:${gameId}`, { config: { private: true }, }) .on('broadcast', { event: 'INSERT' }, (payload) => console.log(payload)) .on('broadcast', { event: 'UPDATE' }, (payload) => console.log(payload)) .on('broadcast', { event: 'DELETE' }, (payload) => console.log(payload)) .subscribe()

使用 Postgres 变更

Postgres 变更使用简单,但随着应用规模扩大会有一些限制。我们建议在大多数场景下使用广播功能。

启用 Postgres 变更

首先需要创建 supabase_realtime 发布,并将要订阅的表添加到该发布中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
begin;-- 移除现有的 supabase_realtime 发布drop publication if exists supabase_realtime;-- 重新创建不含表的 supabase_realtime 发布create publication supabase_realtime;commit;-- 将名为 'messages' 的表添加到发布中-- (请根据您的实际表名修改此处)alter publication supabase_realtime add table messages;

流式插入

您可以使用 INSERT 事件来流式传输所有新增行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// @noImplicitAny: falseimport { createClient } from '@supabase/supabase-js'const supabase = createClient('your_project_url', 'your_supabase_api_key')// ---cut---const channel = supabase .channel('schema-db-changes') .on( 'postgres_changes', { event: 'INSERT', schema: 'public', }, (payload) => console.log(payload) ) .subscribe()

流式更新

您可以使用 UPDATE 事件来流式传输所有更新的行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// @noImplicitAny: falseimport { createClient } from '@supabase/supabase-js'const supabase = createClient('your_project_url', 'your_supabase_api_key')// ---cut---const channel = supabase .channel('schema-db-changes') .on( 'postgres_changes', { event: 'UPDATE', schema: 'public', }, (payload) => console.log(payload) ) .subscribe()