使用 POSTGRES 构建响应式实时应用程序
PG级功能
设置触发器
AWS 安全直播!
关系型数据库……你肯定知道吧?最近我发现了如何使用 PostgreSQL 构建实时应用程序。我迫不及待地想和你们分享。
关于如何让客户端使用 WebSocket 并更新 HTML,之前已经有很多关于响应式编程、前端框架、socket.io 等库以及带有 Redis 发布/订阅功能的 node.js 服务器等的教程进行了讲解。
我第一次看到 Meteor JS 如何监听 MongoDB 的更新,并实时将更新内容呈现在 UI 上时,印象非常深刻。任何应用程序都可以更新集合,前端也能随之更新。我想这启发了 MongoDB 团队实现变更流。
不过现在我终于找到了如何使用Postgres数据库构建这种实时应用程序的方法。方法如下:
PG级功能
关键在于Postgres的两个特性结合使用。首先是触发器(Triggers):它们会监视某个表并在数据库服务器内部执行函数。其次是通知(Notifications):通过通知,您可以从服务器获取事件。如果您已经了解如何使用这两个特性,则可以跳过本文的其余部分。
设置触发器
处理表更新事件的关键在于创建触发器。在 PostgreSQL 中,触发器需要一个函数。因此,我们首先需要创建这个函数。
CREATE OR REPLACE FUNCTION notify_table_update()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS
$$
BEGIN
IF TG_OP = 'INSERT' THEN
PERFORM pg_notify(
'update_' || TG_TABLE_NAME,
'{"new":' || row_to_json(NEW)::text || '}'
);
END IF;
IF TG_OP = 'UPDATE' THEN
PERFORM pg_notify(
'update_' || TG_TABLE_NAME,
'{"new":' || row_to_json(NEW)::text || ',"old":' || row_to_json(NEW)::text || '}'
);
END IF;
IF TG_OP = 'DELETE' THEN
PERFORM pg_notify(
'update_' || TG_TABLE_NAME,
'{"old":' || row_to_json(OLD)::text || '}'
);
END IF;
RETURN null;
END;
$$;
您创建的函数会被调用notify_table_update并返回一个触发器,且不带任何参数。该函数位于 plpgsql 代码中。它使用 pg_notify 函数,并传入一个主题名称和一个包含更新后条目和更新前条目的数据字符串。topic我使用了一个变量,使TG_TABLE_NAME该函数更通用,可以直接用于任何表。TG_OP该变量可在触发器函数中使用。返回值可以是 NULL 或 NULL。触发器函数中还可以使用其他变量,您可以在此页面文档NEW中找到相关信息。
创建触发器的方式与 Postgres 官方文档中的示例完全相同。
CREATE TRIGGER users_notify_trigger
AFTER UPDATE OR INSERT OR DELETE ON users
FOR EACH ROW
EXECUTE PROCEDURE notify_table_update();
这里需要特别注意的是(这一点很难发现),即使没有向函数传递任何参数,该函数仍然可以访问NEW表OLD中的行数据以及其他一些变量。使用“AFTER UPDATE”时,新旧数据都可用。对于插入操作,只有新数据可用;对于删除操作,只有旧数据可用OLD。现在,可以为每种更新类型使用不同的触发器,或者使用上述函数声明中所示的 plpgsql 语法中的 if 语句,以可控的方式进一步减少事件数量,这仍然足以满足您的应用程序的需求。
作为一名JS开发人员,我想介绍如何使用postgres npm模块来使用这些触发器接收事件:
sql.listen('update_user', payload => {
const update = JSON.parse(payload);
});
现在,你已经在 Node.js 中实现了事件处理,一切尽在你的掌控之中。你可以通过 WebSocket 将事件直接推送到前端,过滤事件,通过其他消息系统进行处理,清除 Web 缓存等等。希望这篇文章能帮助你学习如何使用 Postgres 构建更具交互性的实时应用程序,具体取决于你的应用需求。
这些通知功能非常实用,尤其适用于构建具有实时更新 UI 的响应式应用,但 Postgres 触发器绝非最终解决方案,也并非万能方案。当 Node.js 服务器短暂断开连接时,这些事件就会丢失。而在 MongoDB 中,您可以稍后重新获取它们。虽然可以通过同时发送通知并将其插入日志表来克服这一限制,但日志表可能会变得非常庞大,因此可扩展性可能会成为一个问题。
另一个问题是,还需要进行大量的开发工作来处理这些事件,并将它们传递给正确的客户端或报告系统。
你觉得这种方法怎么样?你之前在PG中使用过触发器来发送通知吗?欢迎在评论区留言。
(题图来自Unsplash。)
文章来源:https://dev.to/bias/build-reactive-realtime-apps-with-postgres-49ej