NocoBase 连接外部数据表(FDW):基于 MySQL federated 与 PostgreSQL Foreign Data Wrapper 的远程表接入实战
2026/9/16 11:22:26 网站建设 项目流程

NocoBase 连接外部数据表(FDW):基于 MySQL federated 与 PostgreSQL Foreign Data Wrapper 的远程表接入实战

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

导读

本指南讲解 NocoBase 中「连接外部数据表(FDW)」功能:它基于数据库原生的 Foreign Data Wrapper 技术,把远程 MySQL、MariaDB、PostgreSQL 中的数据表映射为本地数据表使用,适用于跨数据源集成、只读数据共享、遗留系统对接等场景。读完本文,你将掌握 FDW 与「连接数据源」的区别、MySQLfederated引擎与 PostgreSQLpostgres_fdw/mysql_fdw的启用前提、插件安装激活流程,以及「创建数据库服务 → 选择远程表 → 字段同步」的完整操作步骤,并深入理解底层 plugin-collection-fdw 插件的实现原理。

什么是 FDW:连接数据源 vs 连接外部数据表

NocoBase 官方文档对两者做了明确的区分:

  • 连接数据源:与特定数据库或 API 服务建立连接,可以完整使用数据库的特性或 API 提供的服务,数据源作为一个整体被接入。
  • 连接外部数据表:从外部获取数据并映射到本地使用。在数据库领域,这种技术被称为 FDW(Foreign Data Wrapper,外部数据包装器)。它侧重于将远程表当作本地表使用,只能一张一张表地连接。因为是远程访问,使用时会有各种约束和局限。

二者也可以配合使用:前者用于建立与数据源的连接,后者用于跨数据源访问。例如,连接了某个 PostgreSQL 数据源,而这个数据源里恰好有一个表是基于 FDW 创建的外部数据表。

从仓库实现看,该能力由独立插件 plugin-collection-fdw 提供。在 server/plugin.ts 的beforeEnable钩子中,插件会校验主数据库类型:

async beforeEnable() { if (this.db.inDialect('sqlite')) { throw new Error('sqlite does not support foreign data wrapper'); } }

也就是说,SQLite 作为 NocoBase 主数据库时无法启用该插件,FDW 仅支持 MySQL、MariaDB、PostgreSQL 作为主数据库的场景。

支持的数据库组合

MySQL / MariaDB:federated引擎

MySQL 通过federated引擎实现外部表,需要手动激活(默认未开启),支持连接远程 MySQL 及其协议兼容数据库(如 MariaDB)。

PostgreSQL:多种fdw扩展

在 PostgreSQL 中,可通过不同类型的fdw扩展来支持不同的远程数据类型。目前 NocoBase 支持的扩展有:

扩展用途说明
postgres_fdw在 PostgreSQL 中连接远程 PostgreSQL 数据库PostgreSQL 官方内置扩展
mysql_fdw在 PostgreSQL 中连接远程 MySQL 数据库由 EnterpriseDB 维护的开源扩展

其余类型的 fdw 扩展(如file_fdworacle_fdw等)接入 NocoBase 需要在代码中实现相应的适配接口。

从源码结构看,插件通过「Bridge(桥接)」抽象来支撑不同数据库组合。在 server/plugin.ts 的beforeLoad中注册了三组桥接实现:

RemoteLocalBridgeFactory.registerBridge('postgres', 'postgres', PgToPgBridge); RemoteLocalBridgeFactory.registerBridge('mariadb', 'mariadb', MariadbToMariadbBridge); RemoteLocalBridgeFactory.registerBridge('mysql', 'mysql', MySQLToMySQLBridge);

对应的实现文件位于 bridges 目录:

  • pg-to-pg.ts:PostgreSQL → PostgreSQL,基于postgres_fdw
  • mysql-to-mysql.ts:MySQL → MySQL,基于federated引擎;
  • mariadb-to-mariadb.ts:MariaDB → MariaDB;
  • mysql-to-pg.ts:PostgreSQL 主库连接远程 MySQL,对应mysql_fdw
  • remote-local-bridge.ts:桥接的抽象基类与工厂。

前提条件

使用 FDW 功能前,需要满足以下条件:

  1. 如果 NocoBase 的主数据库是 MySQL,则需要激活federated引擎,具体步骤见 MySQL 如何启用 federated 引擎;
  2. 通过插件管理器安装并激活collection-fdw插件。

附:MySQL 如何启用 federated 引擎

MySQL 数据库默认没有开启federated模块,需要修改my.cnf配置。如果使用 Docker 部署,可以通过 volumes 挂载扩展配置。以docker-compose.yml为例:

mysql: image: mysql:8.1.0 volumes: - ./storage/mysql-conf:/etc/mysql/conf.d environment: MYSQL_DATABASE: nocobase MYSQL_USER: nocobase MYSQL_PASSWORD: nocobase MYSQL_ROOT_PASSWORD: nocobase restart: always networks: - nocobase

新建配置文件./storage/mysql-conf/federated.cnf

[mysqld] federated

重启 MySQL 容器使配置生效:

docker compose up -d mysql

最后验证federated是否已经激活:

show engines

如果输出结果中FEDERATED一行的 Support 列为YES,则说明引擎已成功启用。

使用手册:连接外部数据表的完整流程

插件激活后,即可在界面上完成外部数据表的连接。整个流程分为六步。

1. 进入「连接外部数据」

在「数据表管理 > 创建数据表」下拉菜单中,选择「连接外部数据」。

2. 选择或创建数据库服务

在「数据库服务」下拉选项中,选择已存在的数据库服务;如果没有,可以点击「创建数据库服务」。

创建数据库服务时需要填写远程数据库的连接信息,包括数据库类型、主机地址(host)、端口(port)、数据库名(database)、用户名(username)和密码(password)等。

3. 选择远程表

选择数据库服务之后,在「远程表」的下拉选项中,选择需要连接的数据表。这一步由前端组件RemoteTableSelect驱动,服务端通过DatabaseServerModellistRemoteTables()方法实时拉取远程库的表清单(见下文原理章节)。

4. 配置字段信息

选中远程表后,NocoBase 会自动读取远程表的字段结构(列名、类型、是否主键等),你可以在此基础上调整字段映射配置,例如修改字段的 interface 类型、显示名称等。

5. 从远程表同步(结构变更)

如果远程表结构发生变化(新增/删除/修改了列),无需重建连接,直接点击「从远程表同步」即可将最新结构同步到本地。同步对话框会展示结构差异,确认后完成更新。这一能力对应前端组件SyncFieldsAction与服务端的字段描述/同步逻辑。

6. 在界面中使用

完成上述步骤后,外部数据表会像普通数据表一样出现在数据表管理中,可以继续为其创建页面、区块(表格、表单、详情等)和操作按钮,在界面中直接展示和查询远程数据。

说明:上述操作对应的前端交互组件(数据库服务选择、创建/编辑数据库服务、远程表选择、字段预览、字段同步、不支持的字段提示等)均可在 client 组件目录 中找到,包括CreateDatabaseServerAction.tsxEditDatabaseServerAction.tsxDatabaseServerSelect.tsxRemoteTableSelect.tsxPreviewFields.tsxPreviewTable.tsxSyncFieldsAction.tsxUnSupportFields.tsx等。

原理剖析一:数据库服务(Database Server)模型与生命周期

FDW 功能的核心数据模型是databaseServers集合,其定义位于 collections/database-server-collection.ts:

export default defineCollection({ name: 'databaseServers', dataCategory: 'system', dumpRules: 'required', migrationRules: ['overwrite', 'schema-only'], autoGenId: false, model: 'DatabaseServerModel', fields: [ { type: 'string', name: 'name', primaryKey: true }, { type: 'string', name: 'description' }, { type: 'json', name: 'options' }, ], });

每条数据库服务记录以name为主键,远程连接参数(host、port、database、username、password 等)整体存放在optionsJSON 字段中。实际执行逻辑由自定义模型 DatabaseServerModel 承担,它通过事件钩子与数据库操作绑定,见 server/plugin.ts:

  • databaseServers.beforeCreatecreateServer():校验远程连通性,并通过 Bridge 在本地库创建CREATE SERVER/CREATE USER MAPPING等对象;
  • databaseServers.afterUpdateupdateServer():先authenticate()验证新连接,再执行ALTER SERVER ... OPTIONS (SET ...)更新连接参数;
  • databaseServers.afterDestroydestroyServer():执行DROP SERVER IF EXISTS ... CASCADE清理本地对象。

此外,插件注册了databaseServers:testConnection资源动作(plugin.ts),用于在创建服务前测试远程连接:

this.app.resourceManager.registerActionHandlers({ async 'databaseServers:testConnection' { const values = ctx.app.environment.renderJsonTemplate(ctx.action.params.values || {}); const db = new Database({ dialect: app.db.options.dialect, ...values }); try { await db.sequelize.authenticate(); } catch (error) { throw new Error(`Unable to connect to the remote database: ${error.message}`); } ctx.body = { success: true }; await next(); }, });

值得注意的一个细节:连接参数在写入/读取时会经过app.environment.renderJsonTemplate()渲染(见 database-server.ts),这意味着数据库服务的连接参数支持使用环境变量模板,便于在不同部署环境间复用配置。

原理剖析二:Bridge 机制与底层 SQL

「远程库 → 本地库」的映射由 Bridge 抽象完成。以 PostgreSQL → PostgreSQL 的 pg-to-pg.ts 为例,createServer()生成的底层 SQL 展示了完整的 FDW 建链过程:

CREATE EXTENSION IF NOT EXISTS postgres_fdw; CREATE SERVER IF NOT EXISTS "<serverName>" FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host :host, port :port, dbname :database); CREATE USER MAPPING IF NOT EXISTS FOR "<localDbUsername>" SERVER "<serverName>" OPTIONS (user :user, password :password);

createTable()则将远程表的CREATE TABLE定义改写为CREATE FOREIGN TABLE,并附加SERVER ... OPTIONS (schema_name ..., table_name ...)以指向远程对象:

remoteTableDefinition = remoteTableDefinition.replace('CREATE TABLE', 'CREATE FOREIGN TABLE'); remoteTableDefinition = remoteTableDefinition.replace(/\bNOT NULL\b/g, ''); remoteTableDefinition = `${remoteTableDefinition} SERVER "${remoteServerName}" OPTIONS (schema_name '${remoteTableInfo.schema}', table_name '${remoteTableInfo.tableName}')`;

两个细节值得注意:

  1. NOT NULL约束被去除:外部表无法可靠保证远程数据的非空约束,因此在本地定义中去掉了NOT NULL
  2. handle_null_id触发器:对于远程表存在id列且主键使用序列(serial)的场景,代码会在远程库上创建一个BEFORE INSERT触发器set_default_id,当插入的id为 NULL 时自动从序列取下一个值(nextval(sequence_name)),从而保证经由本地写入远程数据时主键的完整性。

外部表集合的元数据行为

外部数据表对应的集合类型是 ForeignDataCollection,它重写了若干默认行为:

  • 构造函数强制autoGenId = falsetimestamps = false:外部表不自动生成本地自增主键和时间戳字段;
  • onDump()为空实现:外部表不参与数据库备份/恢复的数据导出(结构由远程库负责);
  • onSync()是「同步/重建」的核心:先根据remoteServerName找到数据库服务,重建 server,再通过 Bridge 的createTable()依据远程表的实时定义重建本地 FOREIGN TABLE;
  • removeFromDb()在 PostgreSQL 下执行DROP FOREIGN TABLE IF EXISTS ... [CASCADE]后再移除集合定义;
  • 通过field.afterAdd事件,将 interface 为createdAt/updatedAt的字段重新映射为模型的时间戳属性,保证界面上的时间语义正常。

插件的资源权限由 ACL snippetpm.data-source-manager.collection-fdw控制,覆盖databaseServers:*databaseServers.tables:*两类动作(见 plugin.ts)。

注意事项与适用边界

  • 主数据库限制:NocoBase 主库为 SQLite 时无法启用本插件(sqlite does not support foreign data wrapper);
  • MySQL 主库需先激活 federatedfederated引擎默认关闭,必须通过my.cnf/ Docker volumes 挂载federated.cnf并重启生效;
  • 逐表连接:FDW 是一张一张表连接,不是整个数据源接入;每次新增外部表都需要重复「选择数据库服务 → 选择远程表」的流程;
  • 远程访问的天然约束:外部表的查询性能受远程网络往返影响,无法使用本地索引优化,NOT NULL等约束在本地不生效,适合低频查询、数据集成、跨源只读共享等场景;
  • 结构变更需手动同步:远程表结构变化后,本地外部表不会自动更新,需要在界面中执行「从远程表同步」;
  • 环境变量模板:数据库服务的连接参数支持环境变量渲染,生产环境请避免在配置中明文写入敏感信息(如密码),建议通过环境变量注入。

结语

NocoBase 的「连接外部数据表(FDW)」把数据库原生的 Foreign Data Wrapper 能力封装为开箱即用的可视化流程:MySQL 主库通过federated引擎、PostgreSQL 主库通过postgres_fdw/mysql_fdw扩展,均只需在界面上配置数据库服务、选择远程表并同步字段,即可像使用本地表一样使用远程数据。对于需要跨数据源集成、遗留系统对接或数据共享的场景,这是一条无需编写代码即可落地的路径。若需进一步定制(例如接入其他类型的 fdw 扩展),可以从 plugin-collection-fdw 的 Bridge 机制与 bridge 基类 入手扩展实现。

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询