Flutter for OpenHarmony:postgres 直连 PostgreSQL 数据库,实现 Dart 原生的高效读写(数据库驱动) 深度解析与鸿蒙适配指南
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net

前言
虽然移动应用大多使用本地数据库(如 SQLite),但在某些特定场景,比如内部企业应用、数据看板,或者 Serverless 架构中,客户端直接连接远程数据库进行即时查询是非常便捷的。
postgres 是一个纯 Dart 实现的 PostgreSQL 驱动,拥有完整的协议支持,不需要任何原生库绑定(JNI/FFI)。这意味着它不仅能在服务器端(Dart VM)运行完美,同样也能在 Flutter 移动端及 Web 端流畅运行,当然也包括 OpenHarmony。
一、核心特性
- 纯 Dart 实现:零原生依赖,全平台通用。
- SSL/TLS 安全连接:保障数据传输安全。
- 流式查询:支持大结果集的流式读取,避免 OOM。
- 连接池:内置连接池管理,适应高并发场景。
通过 TCP/SSL 连接
PostgreSQL 协议交互
执行 SQL 语句
底层查询
原始结果集
映射后的 Dart 对象
OpenHarmony 应用
远程数据库服务器
内置连接池
数据库实例
Flutter 组件渲染
二、集成与配置
2.1 添加依赖
dependencies:postgres: ^3.5.9 2.2 连接配置 (SSLMode)
在公网环境连接数据库,强烈建议开启 SSL。
import'package:postgres/postgres.dart';final endpoint =Endpoint( host:'db.example.com', port:5432, database:'my_db', username:'user', password:'password',);final connection =awaitConnection.open( endpoint, settings:ConnectionSettings( sslMode:SslMode.require,// 强制 SSL),);
三、核心操作与示例
3.1 示例一:执行简单查询
查询用户列表并将结果映射为 Dart 对象。
Future<void>queryUsers()async{// 假设已有 connectionfinal result =await connection.execute('SELECT id, name FROM users WHERE active = @active', parameters:{'active':true},);for(final row in result){print('User: ${row[0]} - ${row[1]}');}}
3.2 示例二:事务处理
转账操作必须在事务中完成。
Future<void>transferMoney(int fromId, int toId, double amount)async{await connection.runTx((session)async{// 1. 扣款await session.execute('UPDATE accounts SET balance = balance - @amount WHERE id = @from', parameters:{'amount': amount,'from': fromId},);// 2. 加款await session.execute('UPDATE accounts SET balance = balance + @amount WHERE id = @to', parameters:{'amount': amount,'to': toId},);// 如果抛异常,自动回滚});}
3.3 示例三:监听数据库通知 (LISTEN/NOTIFY)
PostgreSQL 有个超酷的功能:发布订阅。App 可以实时收到数据库变更通知。
Future<void>listenChanges()async{// 建立专用连接用于监听final conn =awaitConnection.open(endpoint);// 订阅频道 'user_updates'await conn.execute("LISTEN user_updates");// 监听通知流 conn.channels['user_updates']?.listen((payload){print('收到数据库通知: $payload');// 刷新 UI});}
四、OpenHarmony 平台适配
4.1 网络权限
连接远程数据库必须声明网络权限。
"requestPermissions":[{"name":"ohos.permission.INTERNET"}]4.2 安全与证书
如果在内网且自签名证书,需要在连接时添加受信任的根证书。postgres 库允许通过 SecurityContext 自定义证书验证逻辑。
五、完整实战示例:实时数据看板
本示例将连接一个远程 PostgreSQL 数据库,并展示实时更新的销售数据。每当有新订单插入时(通过 LISTEN/NOTIFY),看板自动刷新。
5.1 示例代码
import'dart:async';import'package:flutter/material.dart';import'package:postgres/postgres.dart';voidmain(){runApp(constMaterialApp(home:DashboardPage()));}classDashboardPageextendsStatefulWidget{constDashboardPage({super.key});@overrideState<DashboardPage>createState()=>_DashboardPageState();}class _DashboardPageState extendsState<DashboardPage>{Connection? _conn;List<Map<String,dynamic>> _salesData =[]; bool _connecting =true;String _error ='';@overridevoidinitState(){super.initState();_connectDB();}Future<void>_connectDB()async{try{// ⚠️ 真实项目中不要硬编码密码!应通过安全方式获取final endpoint =Endpoint( host:'192.168.1.100',// 替换为你的服务器 IP port:5432, database:'sales_db', username:'flutter_app', password:'secure_password',); _conn =awaitConnection.open(endpoint, settings:ConnectionSettings(sslMode:SslMode.disable));// 订阅实时更新await _conn!.execute("LISTEN new_sale"); _conn!.channels['new_sale']?.listen((_)=>_refreshData());await_refreshData();// 初始加载setState((){ _connecting =false; _error ='';});}catch(e){setState((){ _connecting =false; _error ='连接失败: $e';});}}Future<void>_refreshData()async{if(_conn ==null)return;try{final result =await _conn!.execute('SELECT product, amount, created_at FROM sales ORDER BY created_at DESC LIMIT 20');final data = result.map((row)=>{'product': row[0]asString,'amount': row[1]as double,'time': row[2]asDateTime,}).toList();if(mounted){setState(()=> _salesData = data);}}catch(e){print('查询失败: $e');}}@overridevoiddispose(){ _conn?.close();super.dispose();}@overrideWidgetbuild(BuildContext context){returnScaffold( appBar:AppBar(title:constText('实时销售看板')), body: _connecting ?constCenter(child:CircularProgressIndicator()): _error.isNotEmpty ?Center(child:Text(_error, style:constTextStyle(color:Colors.red))):RefreshIndicator( onRefresh: _refreshData, child:ListView.builder( itemCount: _salesData.length, itemBuilder:(context, index){final item = _salesData[index];returnListTile( leading:constIcon(Icons.shopping_cart), title:Text(item['product']), subtitle:Text(item['time'].toString().substring(11,19)), trailing:Text('¥${item['amount']}', style:constTextStyle(fontWeight:FontWeight.bold, fontSize:16, color:Colors.green),),);},),), floatingActionButton:FloatingActionButton( tooltip:'模拟下单', child:constIcon(Icons.add), onPressed:(){// 仅用于演示:客户端插入一条数据触发通知 _conn?.execute("INSERT INTO sales (product, amount) VALUES ('OpenHarmony Device', 999.0); NOTIFY new_sale;");},),);}}
六、总结
在 OpenHarmony 上通过 postgres 库直连数据库,为开发者提供了极大的灵活性,尤其适合快速原型开发、内部工具以及实时性要求极高的场景。
最佳实践:
- 安全性:不要把生产环境数据库端口直接暴露在公网,建议配合 VPN 或 SSH 隧道使用,或者至少限制 IP 白名单。
- 连接池:虽然库内置了连接池,但移动端资源有限,应谨慎开启过多连接。通常一个长连接用于监听,短连接按需使用。
- 架构设计:对于大型 C 端应用,仍建议通过 HTTP API 访问数据,直连仅限特定后端或管理端场景。