-
技术大神们好,我在使用GaussDB时遇到一个监控采集方面的错误,特来求助。我的collector在尝试采集stat_activity指标时失败了,报错信息如下:time=2025-09-10T17:22:38.015+08:00 level=INFO source=namespace.go:235 msg="error finding namespace" err="Error running query on database \"113.44.80.136:8000\": pg_stat_activity ERROR: Column \"wait_event\" does not exist. (SQLSTATE 42703)"相关SQL:SELECT pg_database.datname, tmp.state, tmp2.usename, tmp2.application_name, tmp2.backend_type, tmp2.wait_event_type, tmp2.wait_event, COALESCE(count,0) as count, COALESCE(max_tx_duration,0) as max_tx_duration FROM ( VALUES ('active'), ('idle'), ('idle in transaction'), ('idle in transaction (aborted)'), ('fastpath function call'), ('disabled') ) AS tmp(state) CROSS JOIN pg_database LEFT JOIN ( SELECT datname, state, usename, application_name, backend_type, wait_event_type, wait_event, count(*) AS count, MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration FROM pg_stat_activity GROUP BY datname,state,usename,application_name,backend_type,wait_event_type,wait_event) AS tmp2 ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname错误提示很明确:SQL查询中引用了名为 wait_event 的列,但该列在目标表中不存在。我想了解:问题根因:这是否是因为我的GaussDB版本(或特定模式)中,系统视图或系统表的结构与采集工具期望的不一致?stat_activity 相关的系统视图究竟是哪个?(例如是pg_stat_activity吗?)这个视图在当前版本的GaussDB中是否不包含 wait_event 列?解决方案:对于这类监控指标采集,GaussDB的正确实践是什么?是需要查询不同的系统视图,还是需要启用特定的监控开关或配置?版本差异:wait_event 列是否是某些更新版本中才加入的?我当前使用的GaussDB版本可能是什么?任何关于此问题的排查思路、系统视图结构说明或版本兼容性信息都将非常有帮助!感谢!背景信息/补充说明(可选):我使用的GaussDB版本是:gaussdb (GaussDB Kernel 505.2.1 build ff07bff6) compiled at 2024-12-27 09:22:42 commit 10161 last mr 21504 release采集工具是:Prometheus gaussdb_exporter希望得到大家的指点,谢谢!
-
技术大神们好,我在使用GaussDB时遇到一个监控采集方面的错误,特来求助。我的collector在尝试采集stat_activity指标时失败了,报错信息如下:time=2025-09-10T15:47:07.742+08:00 level=INFO source=namespace.go:235 msg="error finding namespace" err="Error running query on database \"113.44.80.136:8000\": pg_stat_activity ERROR: Column \"wait_event_type\" does not exist. (SQLSTATE 42703)"相关SQL:SELECT pg_database.datname, tmp.state, tmp2.usename, tmp2.application_name, tmp2.backend_type, tmp2.wait_event_type, tmp2.wait_event, COALESCE(count,0) as count, COALESCE(max_tx_duration,0) as max_tx_duration FROM ( VALUES ('active'), ('idle'), ('idle in transaction'), ('idle in transaction (aborted)'), ('fastpath function call'), ('disabled') ) AS tmp(state) CROSS JOIN pg_database LEFT JOIN ( SELECT datname, state, usename, application_name, backend_type, wait_event_type, wait_event, count(*) AS count, MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration FROM pg_stat_activity GROUP BY datname,state,usename,application_name,backend_type,wait_event_type,wait_event) AS tmp2 ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname错误提示很明确:SQL查询中引用了名为 wait_event_type 的列,但该列在目标表中不存在。我想了解:问题根因:这是否是因为我的GaussDB版本(或特定模式)中,系统视图或系统表的结构与采集工具期望的不一致?stat_activity 相关的系统视图究竟是哪个?(例如是pg_stat_activity吗?)这个视图在当前版本的GaussDB中是否不包含 wait_event_type 列?解决方案:对于这类监控指标采集,GaussDB的正确实践是什么?是需要查询不同的系统视图,还是需要启用特定的监控开关或配置?版本差异:wait_event_type 列是否是某些更新版本中才加入的?我当前使用的GaussDB版本可能是什么?任何关于此问题的排查思路、系统视图结构说明或版本兼容性信息都将非常有帮助!感谢!背景信息/补充说明(可选):我使用的GaussDB版本是:gaussdb (GaussDB Kernel 505.2.1 build ff07bff6) compiled at 2024-12-27 09:22:42 commit 10161 last mr 21504 release采集工具是:Prometheus gaussdb_exporter希望得到大家的指点,谢谢!
-
技术大神们好,我在使用GaussDB时遇到一个监控采集方面的错误,特来求助。我的collector在尝试采集stat_activity指标时失败了,报错信息如下:time=2025-09-05T09:34:16.780+08:00 level=INFO source=namespace.go:235 msg="error finding namespace" err="Error running query on database \"113.44.80.136:8000\": pg_stat_activity ERROR: Column \"backend_type\" does not exist. (SQLSTATE 42703)"相关SQL:SELECT pg_database.datname, tmp.state, tmp2.usename, tmp2.application_name, tmp2.backend_type, tmp2.wait_event_type, tmp2.wait_event, COALESCE(count,0) as count, COALESCE(max_tx_duration,0) as max_tx_duration FROM ( VALUES ('active'), ('idle'), ('idle in transaction'), ('idle in transaction (aborted)'), ('fastpath function call'), ('disabled') ) AS tmp(state) CROSS JOIN pg_database LEFT JOIN ( SELECT datname, state, usename, application_name, backend_type, wait_event_type, wait_event, count(*) AS count, MAX(EXTRACT(EPOCH FROM now() - xact_start))::float AS max_tx_duration FROM pg_stat_activity GROUP BY datname,state,usename,application_name,backend_type,wait_event_type,wait_event) AS tmp2 ON tmp.state = tmp2.state AND pg_database.datname = tmp2.datname错误提示很明确:SQL查询中引用了名为 backend_type 的列,但该列在目标表中不存在。我想了解:问题根因:这是否是因为我的GaussDB版本(或特定模式)中,系统视图或系统表的结构与采集工具期望的不一致?stat_activity 相关的系统视图究竟是哪个?(例如是pg_stat_activity吗?)这个视图在当前版本的GaussDB中是否不包含 backend_type 列?解决方案:对于这类监控指标采集,GaussDB的正确实践是什么?是需要查询不同的系统视图,还是需要启用特定的监控开关或配置?版本差异:backend_type 列是否是某些更新版本中才加入的?我当前使用的GaussDB版本可能是什么?任何关于此问题的排查思路、系统视图结构说明或版本兼容性信息都将非常有帮助!感谢!背景信息/补充说明(可选):我使用的GaussDB版本是:gaussdb (GaussDB Kernel 505.2.1 build ff07bff6) compiled at 2024-12-27 09:22:42 commit 10161 last mr 21504 release采集工具是:Prometheus gaussdb_exporter希望得到大家的指点,谢谢!
-
技术大神们好,我在使用GaussDB时遇到一个监控采集方面的错误,特来求助。我的collector在尝试采集stat_database指标时失败了,报错信息如下:time=2025-09-05T09:34:16.484+08:00 level=ERROR source=collector.go:207 msg="collector failed" name=stat_database duration_seconds=0.1799696 err="ERROR: Column \"active_time\" does not exist. (SQLSTATE 42703)"错误提示很明确:SQL查询中引用了名为 active_time 的列,但该列在目标表中不存在。相关SQL:SELECT datid, datname, numbackends, xact_commit, xact_rollback, blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, tup_updated, tup_deleted, conflicts, temp_files, temp_bytes, deadlocks, blk_read_time, blk_write_time, stats_reset, active_timeFROM pg_stat_database;我想了解:问题根因:这是否是因为我的GaussDB版本(或特定模式)中,系统视图或系统表的结构与采集工具期望的不一致?stat_database 相关的系统视图究竟是哪个?(例如是pg_stat_database吗?)这个视图在当前版本的GaussDB中是否不包含 active_time 列?解决方案:对于这类监控指标采集,GaussDB的正确实践是什么?是需要查询不同的系统视图,还是需要启用特定的监控开关或配置?版本差异:active_time 列是否是某些更新版本中才加入的?我当前使用的GaussDB版本可能是什么?任何关于此问题的排查思路、系统视图结构说明或版本兼容性信息都将非常有帮助!感谢!背景信息/补充说明(可选):我使用的GaussDB版本是:gaussdb (GaussDB Kernel 505.2.1 build ff07bff6) compiled at 2024-12-27 09:22:42 commit 10161 last mr 21504 release采集工具是:Prometheus gaussdb_exporter希望得到大家的指点,谢谢!
-
在华为云CCE(云容器引擎)中,通过Web界面创建负载能成功而直接在计算节点后台使用containerd命令拉取镜像失败,通常是由于Web界面创建负载时,系统会自动处理镜像拉取所需的网络、认证和配置,而手动在节点上使用containerd命令则可能缺乏这些必要的配置或环境。 1. Web界面创建负载成功的原因通过CCE控制台创建负载(如Deployment)时,系统会自动完成以下操作,确保镜像拉取成功:镜像拉取策略(Image Pull Policy):在创建工作负载时,您可以配置镜像拉取策略(如Always、IfNotPresent)。如果未显式设置,Kubernetes默认策略为Always,即每次启动容器时都会尝试从镜像仓库拉取最新镜像。但Web界面创建时,系统会智能处理策略,避免因本地镜像缺失导致失败。自动使用镜像拉取密钥(ImagePullSecrets):如果镜像来自私有仓库(如华为云SWR或第三方仓库),Web界面创建负载时会自动注入认证密钥(如default-secret用于华为云SWR仓库)。这提供了必要的身份凭证,使拉取操作得以授权。而手动命令若未指定密钥,会因认证失败被拒绝。网络代理或加速器配置:CCE集群可能配置了镜像加速器或代理(如通过修改containerd的config.toml或设置image-pull-progress-timeout参数),以优化拉取过程或绕过网络限制。Web界面创建的负载会利用这些集群级配置,而手动命令可能未应用这些设置。节点网络权限:集群节点可能通过NAT网关、弹性IP或VPN访问公网或特定镜像仓库。Web界面创建的负载继承集群网络设置,而手动命令可能因节点网络配置问题(如路由缺失、防火墙规则)导致超时或连接失败。2. 手动使用containerd命令失败的原因及解决方案在节点后台直接使用ctr(containerd的命令行工具)拉取镜像时,常见失败原因包括:镜像地址错误或不存在:确保镜像地址完整且正确(包括仓库URL、命名空间、镜像名和标签)。例如,拉取华为云SWR镜像需使用完整格式:swr.<region>.myhuaweicloud.com/<namespace>/<image>:<tag>。操作建议:核对镜像地址,尝试通过Web界面获取准确的拉取指令。认证问题(私有镜像):手动命令需显式提供认证信息。若未登录或未指定密钥,会返回denied或401 Unauthorized错误。解决方案:对于华为云SWR镜像,使用crictl或ctr时通过--user参数指定用户名和密码(通常为IAM用户名和令牌):ctr -n k8s.io images pull --user <username>:<password> <image-url>对于第三方私有仓库,需先在集群中创建Secret,并在命令中引用或直接配置认证文件。网络连接问题:手动拉取可能因节点网络配置不当(如DNS解析失败、路由缺失或防火墙拦截)而失败,错误信息可能包含dial tcp timeout或no such host。解决方案:检查节点网络:确保节点可访问镜像仓库(例如,通过ping或curl测试连通性)。若集群使用代理或加速器,手动配置containerd以应用这些设置。具体步骤:编辑/etc/containerd/config.toml,在[plugins."io.containerd.grpc.v1.cri".registry.mirrors]下为仓库添加镜像端点(如加速器地址)。重启containerd:systemctl restart containerd。对于公网镜像,确保节点有公网访问能力(如绑定EIP或配置SNAT)。磁盘空间不足:节点磁盘空间耗尽会导致拉取失败,错误信息可能提示no space left on device。解决方案:清理节点磁盘(如删除未使用的容器或镜像),或扩容磁盘。containerd兼容性问题:某些旧格式镜像(如使用application/octet-stream mediaType的层)可能不被containerd支持。解决方案:重新使用高版本Docker(>=v1.11)打包镜像,确保使用现代格式。3. 问题排查步骤若手动拉取持续失败,建议按以下顺序排查:检查镜像地址和标签:确认镜像存在且地址正确。验证网络连通性:ping <registry-host> # 测试网络可达性nslookup <registry-host> # 检查DNS解析检查认证配置:对于私有镜像,确保使用正确的用户名/密码或Secret。在CCE控制台查看负载配置中使用的imagePullSecrets。查看containerd配置:确认/etc/containerd/config.toml中是否配置了正确的镜像加速器或代理。检查image-pull-progress-timeout参数是否设置过短(建议延长超时时间)。检查节点资源:使用df -h查看磁盘空间。使用crictl ps -a或docker ps -a检查是否有残留容器占用资源。查看详细错误日志:使用ctr -n k8s.io images pull --debug <image-url>获取详细错误信息。在节点上查看containerd日志:journalctl -u containerd --no-pager -n 100。总结一下下通过Web界面创建负载能成功拉取镜像,是因为CCE自动处理了认证、网络加速、资源调度等底层细节。而手动使用containerd命令失败,通常是由于:缺乏自动注入的认证密钥(imagePullSecrets)未应用集群配置的镜像加速器或网络代理命令参数或环境配置不正确1、确认镜像地址正确性:使用与 web 界面相同的完整镜像地址(如包含 SWR 地域域名的地址)。 2、配置仓库认证:通过nerdctl login swr.cn-xxx.myhuaweicloud.com输入 SWR 的访问密钥(AK/SK),或通过ctr credentials set配置认证。 3、检查网络连通性:在节点执行curl -v https://镜像仓库地址,确认网络和端口(443)是否通畅。 4、指定 namespace:CCE 中容器通常运行在k8s.io命名空间下,拉取时可指定ctr -n k8s.io images pull 镜像地址。
-
GaussDB(尤其是华为 GaussDB (for PostgreSQL)、GaussDB 300 等企业级分布式版本)作为面向高可用场景的数据库,其 DN(Data Node,数据节点)的主备同步是保障数据一致性与服务连续性的核心机制。根据不同版本和部署场景,GaussDB 支持物理同步和逻辑同步两大类主备同步方式。 一、核心的同步方式:物理的同步(主流的高可用选择)物理同步是 GaussDB DN 主备同步的默认且最常用方式,其核心是基于 “物理数据块复制” 实现主备数据一致性,本质是主库将物理变更(如数据页修改、事务日志)实时同步到备库,备库以 “物理镜像” 方式恢复数据,确保主备数据完全一致(字节级一致)。1. 具体实现原理物理同步依赖 GaussDB 的WAL(Write-Ahead Logging,预写日志)机制,全流程可拆解为 3 个关键步骤:步骤 1:主库生成 WAL 日志主库上所有数据修改操作(如 INSERT/UPDATE/DELETE、DDL 语句),会先写入 WAL 日志(顺序写入,性能高效),再落盘到实际数据文件。WAL 日志记录的是 “物理层面的变更指令”(如 “修改数据页 X 的偏移量 Y 为值 Z”),而非逻辑 SQL 语句。步骤 2:WAL 日志同步到备库主库通过专用的 “日志发送进程(WALSender)”,将实时生成的 WAL 日志按 “段(Segment)” 或 “流式(Stream)” 方式推送到备库;备库则通过 “日志接收进程(WalReceiver)” 监听并接收 WAL 日志,暂存到本地的 “备库 WAL 缓冲区”。步骤 3:备库恢复 WAL 日志备库的 “恢复进程(Startup Process)” 读取本地暂存的 WAL 日志,按照与主库相同的物理顺序 “重放(Replay)” 日志中的变更指令 —— 即还原主库的数据修改操作,将变更应用到备库的数据文件中,最终实现主备数据的物理一致。 2. 关键的特性(适配高可用场景)数据强一致性:备库是主库的物理镜像,无数据语义偏差,支持 “故障无缝切换”(主库故障后,备库可直接接管服务,无需数据修复);低延迟:采用 “流式同步” 时,主库生成 WAL 日志后会实时推送给备库,同步延迟通常在毫秒级,适配金融、电商等对实时性要求高的场景;支持 “同步 / 异步” 模式切换:同步模式:主库需等待备库确认 WAL 日志已接收并落盘后,才向应用返回 “事务提交成功”,确保数据零丢失(RPO=0);异步模式:主库提交事务后立即返回,WAL 日志异步推送给备库,牺牲少量一致性换取更低的主库响应延迟(适用于非核心业务)。 二、补充的同步方式:逻辑同步(灵活的场景适配)逻辑同步是基于 “逻辑数据变更” 的同步方式,核心是主库将数据修改操作解析为 “逻辑事件”(如 “对表 T 插入一行数据(id=1, name='A')”),备库通过解析逻辑事件重建数据,不依赖物理数据块结构。1. 具体实现原理逻辑同步依赖 GaussDB 的逻辑解码(Logical Decoding)功能,实现流程与物理同步差异显著:步骤 1:主库逻辑解码 WAL 日志主库开启 “逻辑解码” 后,WAL 日志不再仅记录物理变更,而是会被 “逻辑解码插件”(如 GaussDB 内置的pg_logical插件)解析为 “逻辑变更事件”—— 即提取 SQL 操作的语义(表名、字段、变更值等),生成结构化的逻辑日志(如 JSON/ProtoBuf 格式)。步骤 2:逻辑日志传输主库的 “逻辑日志发送进程” 将解析后的逻辑变更事件,通过专用协议(如基于 TCP 的逻辑复制协议)发送到备库(或其他目标端,如异构数据库、数据仓库)。步骤 3:备库应用逻辑事件备库的 “逻辑日志应用进程” 接收逻辑变更事件后,根据事件中的表结构和变更内容,生成对应的 SQL 语句(如 INSERT/UPDATE),并执行该 SQL 以修改备库数据,最终实现主备数据的逻辑一致。 2. 关键的特性(适配灵活场景)跨版本 / 跨结构同步:逻辑同步不依赖物理数据页格式,支持主备库不同 minor 版本(如主库 2.0、备库 2.1),甚至可同步到表结构略有差异的备库(如备库比主库多非关键字段);支持 “部分数据同步”:可指定同步某几张表、某类数据(如按分区过滤),无需同步整个 DN 的所有数据(适用于数据分片、读写分离场景,如备库仅同步查询高频表);兼容异构目标端:逻辑日志可同步到非 GaussDB 的系统(如 Elasticsearch、Hadoop),用于数据备份、数据分析等场景,但数据一致性弱于物理同步(可能存在语义解析偏差)。 三、一些个特殊的场景:混合同步策略(部分版本支持)为了平衡 “一致性” 和 “灵活性”,部分 GaussDB 版本(如 GaussDB 100)支持 “物理 + 逻辑” 混合同步,典型场景如:主备库用物理同步(保障核心数据一致):核心业务的 DN 主备采用物理同步,确保故障切换无数据丢失;从备库用逻辑同步(扩展数据用途):在备库上开启逻辑解码,将部分表的逻辑变更同步到只读节点或数据仓库,用于报表查询、数据分析,避免影响主库性能。 对比一下下对比维度物理同步逻辑同步同步对象物理 WAL 日志(数据块变更指令)逻辑变更事件(SQL 语义)数据一致性强一致(物理镜像,RPO=0)弱一致(逻辑重建,可能有语义偏差)延迟性能低延迟(毫秒级,流式同步)中延迟(需解码 + 生成 SQL,毫秒~秒级)适用场景高可用主备切换(金融、核心业务)部分数据同步、跨系统集成跨版本兼容性低(依赖物理页格式,同版本优先)高(不依赖物理格式,跨 minor 版本) 总结一下下GaussDB 的 DN 主备同步以物理同步为核心保障高可用,以逻辑同步为补充适配灵活场景,用户可根据业务的 “一致性要求、实时性需求、跨系统需求” 选择对应的同步方式。
-
案例介绍本案例选择Flask作为后端服务,并借助开发者空间云开发环境提供的免费GaussDB数据库和HCE2.0开发环境进行本地部署,便捷地提供了一种能够保障题库安全的在线考试系统。案例内容一、概述1.1 案例介绍Flask是一个用Python编写的轻量级Web应用框架。它被称为“微框架”,核心功能简单,提供了构建Web应用所需的最少工具。华为开发者空间,是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云开发环境、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者 从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。GaussDB是华为自主创新研发的分布式关系型数据库。该产品支持分布式事务,同城跨AZ部署,数据0丢失,支持1000+的扩展能力,PB级海量存储。同时拥有云上高可用,高可靠,高安全,弹性伸缩,一键部署,快速备份恢复,监控告警等关键能力,能为企业提供功能全面,稳定可靠,扩展性强,性能优越的企业级数据库服务.本案例借助开发者空间云开发环境,通过Flask与开发者空间提供的免费GaussDB数据库实例对接,直接使用 SQL 语句对GaussDB 数据库实例进行操作,完成一个现代化 Web 应用构建。1.2 适用对象企业个人开发者高校学生1.3 案例时间本案例总时长预计40分钟。1.4 案例流程 说明:申请华为云开发者空间的GaussDB数据库;进行华为云开发者空间的云开发环境进行文件创建与编辑;启用Flask Web 服务,适配GaussDB,在GaussDB在线操作页面建表于插入题目数据。1.5 资源总览本案例预计花费0.33元。资源名称规格单价(元)时长(分钟)华为开发者空间 - 云开发环境鲲鹏通用计算增强型 kc1 | 2vCPUs | 4G | HCE2.0免费40华为开发者空间 - 生态版GaussDB单副本集中式版 | 4 vCPUs | 16G | HCE OS 64bit (200GB)免费40弹性公网IP按需计费 5Mbit/s0.33元/时40 二、案例准备工作2.1 配置云开发环境根据案例《开发者空间 - 云开发环境使用指导》,请查看下面链接,配置云开发环境,并通过vscode链接工具登录云开发环境。本地VSCode基于华为开发者空间云开发环境完成小程序开发2.1 领取免费版GaussDB免费领取GaussDB在线试用版(2025年06月 21日 - 2025年 12月 31日),有1000个名额,数量有限,链接如下:免费领取GaussDB在线试用版(1-3工作日内报名审核通过后会有短信通知)(1)报名申请审核通过后,进入开发者空间工作台,会有GaussDB免费试用提示,点击立即开通即可。(2)填写GaussDB数据库开通参数:虚拟私有云:如下图到控制台创建,采用默认参数即可。安全组:采用默认安全组。管理员密码:自定义设置,保存好后续使用。(3)设置完后点击开通,开通成功后如下图提示:(4)开通成功后,点击立即前往进入GaussDB数据库实例页面,等待状态切换为"正常",如下图所示: (5)绑定弹性公网EIP,如果需要远程操作数据库必须要绑定公网EIP(EIP需购买,按需计费0.33元/小时,以控制台为准)点击数据库实例名称,进入GaussDB的基本信息界面: 点击绑定弹性公网IP,若开发者没有购买,则需要购买弹性公网IP。购买时选择按需计费,购买成功后截图如下:回到数据库基本信息界面,再次绑定公网IP,绑定成功截图如下:2.2 验证云开发环境与GaussDB互通通过xshell或windows命令终端登录云开发环境,测试GaussDB能否连接,如下是通 2.3 登录GaussDB数据库回到云数据库控制台,登录数据库:点击登录,再点击同意并继续输入密码,点击测试连接,再次点击登录,即可登录成功2.3.1 新建数据库登录成功后,点击新建数据库输入数据库名称 test 点击 确定 按钮,数据库创建成功: 2.3.2 创建数据库表点击 SQL操作,点击SQL查询库名选择test,Schema选择 public ,执行以下SQL语句,创建表:CREATE TABLE t_question ( id SERIAL PRIMARY KEY, question_text TEXT NOT NULL, option_a VARCHAR(255) NOT NULL, option_b VARCHAR(255) NOT NULL, option_c VARCHAR(255) NOT NULL, option_d VARCHAR(255) NOT NULL, correct_answer CHAR(1) NOT NULL);创建表成功:向表中插入测试题目和答案INSERT INTO t_question (question_text, option_a, option_b, option_c, option_d, correct_answer)VALUES ('华为云的旗舰数据库服务是什么?', 'RDS for MySQL', 'GaussDB', 'DWS', 'TaurusDB', 'B'), ('在华为云上,用于管理容器化应用的PaaS服务叫什么?', 'CCE', 'ECS', 'OBS', 'ELB', 'A'), ('华为云上用于对象存储的服务名称是?', 'SFS', 'EVS', 'OBS', 'VPC', 'C');执行SQL,插入成功:查询表中数据:SELECT *FROM t_question删除指定题目:DELETE FROM t_questionWHERE id = 1;再执行查询的SQL语句:SELECT *FROM t_question可以看到已成功删除id为1的数据。 三、 Flask部署与Python驱动安装通过本地IDE连接云开发环境,参考使用VSCode连接云开发环境通过VSCode连接成功后,打开终端 3.1 创建项目虚拟环境因为业务场景的Python开发,多数都是构建一个大型应用程序,并且不希望各种组件的各种版本之间相互冲突,所以需要设置一个虚拟环境。先需要更新下载源。执行如下命令 sudo yum -y updatesudo yum -y upgradepip3 install virtualenv -i https://repo.huaweicloud.com/repository/pypi/simple/ #安装virtualenvpython3 -m venv myenv #创建虚拟环境source myenv/bin/activate #激活环境 环境激活后,用户名前会有(myenv)字样,如上图所示。3.2 安装Flask Web 框架。安装之前,需要更新下pip。python3 -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simplepip3 install flask -i https://pypi.tuna.tsinghua.edu.cn/simple3.3 安装GaussDB数据库对应的Python驱动GaussDB数据库对应的Python驱动为psycopg2。即Flask Web 框架允许通过psycopg2驱动,连接GaussDB数据库,并操作数据对象。不建议直接用pip去安装psycopg2驱动。1.从华为云GaussDB数据库官方文档中下载驱动。wget https://dbs-download.obs.cn-north-1.myhuaweicloud.com/GaussDB/1750076538851/GaussDB_driver.zipunzip GaussDB_driver.zipcd GaussDB_driver/Centralized/Hce2.0_arm_64/tar zxvf GaussDB-Kernel_505.2.1_Hce_64bit_Python.tar.gz 解压后有两个文件夹:psycopg2:psycopg2库文件。lib:lib库文件。2.使用root用户将psycopg2复制到python安装目录下的site-packages文件夹下。sudo cp psycopg2 $(python3 -c 'import site; print(site.getsitepackages()[0])') -r3.修改psycopg2目录权限为755。sudo chmod 755 $(python3 -c 'import site; print(site.getsitepackages()[0])')/psycopg2 -R4.将psycopg2目录添加到环境变量$PYTHONPATH,并使之生效。export PYTHONPATH=$(python3 -c 'import site; print(site.getsitepackages()[0])'):$PYTHONPATH5.将解压后的上述lib目录,配置在环境变量LD_LIBRARY_PATH中。本案例对应的lib目录是/home/xxx/GaussDB_driver/Centralized/Hce2.0_arm_64/lib,读者根据自己实际情况做修改export LD_LIBRARY_PATH=/home/xxx/GaussDB_driver/Centralized/Hce2.0_arm_64/lib:$LD_LIBRARY_PATH6.复制驱动到 python 的 site-packagessudo cp -r /home/developer/GaussDB_driver/Centralized/Hce2.0_arm_64/psycopg2 \ /usr/lib/python3.9/site-packages/7.修改权限sudo chmod -R 755 /usr/lib/python3.9/site-packages/psycopg2注意:如果引入psycopg2报找不到libpq.so.5.5,是因为环境变量LD_LIBRARY_PATH没有包含libpq.so.5.5的目录路径,由于上述步骤5用export设置的临时环境变量,所以在新的会话中需要重新设置LD_LIBRARY_PATH指定之前解压的驱动lib目录3.4 通过本地IDE创建Flask Web工程在IDE里终端窗口创建web项目并进入。mkdir ~/testcd ~/test3.5 创建test项目的Web应用(1)在test的项目目录里,创建app.py文件和子目录templates以及templates下的index.html app.py:文件作为考试系统的后端,与GaussDB进行通信,对前端index.html提供数据index.html:用来展示题目与选项 (2)把以下代码复制粘贴到app.py,注意修改为自己的GaussDB的ip、账号、密码、数据库from flask import Flask, render_template, request, jsonifyimport psycopg2import psycopg2.extrasapp = Flask(__name__)# Database connection configurationdb_config = { 'host': 'your_gaussdb_host', 'user': 'your_user', 'password': 'your_password', 'database': 'test', 'port': 8000}def get_db_connection(): """Establish database connection""" conn = psycopg2.connect(**db_config) return conn@app.route('/')def index(): """Home route: Display all exam questions""" conn = get_db_connection() cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cursor.execute('SELECT * FROM t_question') questions = cursor.fetchall() cursor.close() conn.close() return render_template('index.html', questions=questions)@app.route('/submit_all_answers', methods=['POST'])def submit_all_answers(): """Submit all answers route: Check if user answers are correct""" answers = {} # Dictionary to store question IDs and user answers correct_count = 0 # Loop through all the answers in the form data for question_index in range(1, len(request.form) // 2 + 1): question_id = request.form[f"question_id_{question_index}"] user_answer = request.form.get(f"answer_{question_index}") conn = get_db_connection() cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) cursor.execute('SELECT correct_answer FROM t_question WHERE id = %s', (question_id,)) result = cursor.fetchone() if result: correct_answer = result['correct_answer'] if user_answer == correct_answer: correct_count += 1 cursor.close() conn.close() return jsonify({ 'message': f'You answered {correct_count} questions correctly!', 'correct_count': correct_count })if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=8080)(3)把以下代码复制粘贴到index.html中<!DOCTYPE html><html><head> <title>在线考试系统</title> <style> body { font-family: Arial, sans-serif; background-color: #f4f7fa; margin: 0; padding: 0; } .container { max-width: 900px; margin: 50px auto; background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } h1 { text-align: center; color: #333; } .question-container { border-bottom: 1px solid #ccc; margin-bottom: 20px; padding-bottom: 15px; } .question-container p { font-size: 18px; margin: 10px 0; } .question-container label { display: block; font-size: 16px; margin-bottom: 8px; } .question-container input[type="radio"] { margin-right: 10px; } .submit-btn { background-color: #4CAF50; color: white; padding: 12px 24px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; } .submit-btn:hover { background-color: #45a049; } </style></head><body> <div class="container"> <h1>在线考试</h1> <form action="/submit_all_answers" method="post"> {% for question in questions %} <div class="question-container"> <p><strong>{{ loop.index }}. {{ question.question_text }}</strong></p> <input type="hidden" name="question_id_{{ loop.index }}" value="{{ question.id }}"> <label><input type="radio" name="answer_{{ loop.index }}" value="A"> A. {{ question.option_a }}</label> <label><input type="radio" name="answer_{{ loop.index }}" value="B"> B. {{ question.option_b }}</label> <label><input type="radio" name="answer_{{ loop.index }}" value="C"> C. {{ question.option_c }}</label> <label><input type="radio" name="answer_{{ loop.index }}" value="D"> D. {{ question.option_d }}</label> </div> {% endfor %} <div style="text-align: center;"> <input type="submit" value="提交所有答案" class="submit-btn"> </div> </form> </div></body></html>(4)然后在终端中运行python3 app.py 在浏览器中打开http://127.0.0.1:8080即可看到在线考试页面 四、释放资源1. 删除虚拟私有云VPC进入虚拟私有云控制台,点击全选按钮,点击“删除”,会弹出关联资源列表的对话框,删除子网和弹性公网IP2. 删除弹性公网IP EIP进入弹性公网IP控制台,首先解绑弹性公网IP,然后删除。3. 删除GaussDB数据库实例进入GaussDB控制台,点击“更多 -> 删除实例”。注意:删除的实例会被移至回收站,但达到回收站策略设置的天数后,该实例会被永久删除,请谨慎操作。 至此,基于华为开发者空间云开发环境+GaussDB实现在线考试系统案例已全部完成。我正在参加【案例共创】第6期 开发者空间-基于云开发环境和GaussDB构建应用 cid:link_3
-
案例介绍 “旅游小助手”微信小程序是一款帮助旅游者,在途中随时拍照后关联一首此景点的唐诗宋词,增长旅游者的文化素养。 开发工具是使用一个微信小程序开发工具IDE,申请了APP ID,可以专注于编写应用程序,最后在平台上仿真模拟,再上传发布。本案例在微信小程序开发工具上开发了应用功能部分,并与开发者空间提供的免费GaussDB数据库实例对接,完成一个小程序开发。华为开发者空间是为全球开发者打造的专属开发者空间,致力于为每位开发者提供一台云开发环境、一套开发工具和云上存储空间,汇聚昇腾、鸿蒙、鲲鹏、GaussDB、欧拉等华为各项根技术的开发工具资源,并提供配套案例指导开发者 从开发编码到应用调测,基于华为根技术生态高效便捷的知识学习、技术体验、应用创新。 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)华为开发者空间 - 云开发环境鲲鹏通用计算增强型 kc1 | 2vCPUs | 4G | euler,22免费60华为开发者空间 - 生态版GaussDB单副本集中式版 | 4 vCPUs | 16G | HCE OS 64bit (200GB)免费60微信开发工具平台stable 1.06.202504020免费 案例适用对象和开发时间1.1 适用对象企业个人开发者高校学生1.2 案例时间本案例总时长预计1个小时。案例方案1.3任务分析小程序连接华为云GaussDB数据库,用于存储识别结果或用户数据,由小程序进行用户交互,把数据存放到数据库。1.4 技术方案 使用华为云数据库服务SDK,通过API网关或云函数访问实现增删改查基本操作。首先要创建华为云数据库实例获取连接配置信息编写数据访问层代码,安全考虑,数据库连接信息不能暴露在前端,需要使用HTTPS安全连接,实现访问权限控制。集成方式通过云函数封装数据库操作小程序调用云函数接口。以下是云数据库步骤:1、需要创建数据库表结构,2、配置华为云环境,3、测试数据库连接。方案还要增加安全增强,添加连接池管理,实现参数化查询防注入,添加操作日志记录功能。1.5 方案还要性能优化:连接复用和查询优化错误增加重试机制,包括:需要添加日志管理功能、实现数据库迁移脚本、添加性能监控。其中,日志管理需求:操作审计日志、错误详细记录和查询性能日志;迁移需求: 版本化数据库变更、回滚支持和环境一致性;添加监控指标:连接池状态、查询耗时和错误率。1.6 集成方案需要集成到主流程添加错误处理中间件实现请求追踪1.7 监控扩展告警规则日志分级敏感信息过滤 测试方案部分包括单元测试中间件、集成测试API流程和模拟错误场景1.8 部署准备环境变量配置、启动脚本优化、健康检查接口并且需要集成健康检查到主服务添加API测试用例实现自动化测试流程1.9健康检查集成方案添加/health端点服务启动自检就绪/存活探针最后进行API测试,数据操作测试错误场景覆盖性能基准测试,1.10 CI/CD准备测试脚本配置覆盖率报告质量门禁,同时编写部署文档配置CI/CD流水线压力测试,检查README内容完整性确认部署步骤准确性验证示例命令有效性。注意后续优化,添加更多使用场景示例补充故障排查指南完善API文档细节。 1.11 交付完成打包完整项目生成文档 附录小程序代码结构d:/企业/鸿蒙生态/ ├── app.js ├── app.json├── app.wxss └── pages/ └── index/ ├── index.js ├── index.json ├── index.wxml └── index.wxss项目文件目录结构我正在参加【案例共创】第6期 开发者空间-基于云开发环境和GaussDB构建应用 cid:link_3
-
GaussDB 中的 版本号、数据库引擎版本 和 内核引擎版本 是三个层级分明且紧密关联的概念,它们共同描述了 GaussDB 数据库实例的技术构成和演进状态。1.一些小概念和定义GaussDB 版本号(产品版本)指华为云发布的 完整产品版本标识,通常格式为 24.7.30.10或 24.1.30,代表 GaussDB 产品的整体发布版本。它对应华为云 Stack(如 8.5.0)或云服务的特定迭代,包含数据库引擎、管理控制台、API 等全栈组件。作用:标记产品功能集、生命周期(如 EOM/EOFS/EOS)及兼容性。数据库引擎版本(DB Engine Version)指 GaussDB 数据库服务的核心软件版本,格式为 V2.0-A.BCD(如 V2.0-8.202.0),其中:V2.0:第二代架构标识;A:年度需求基线(如 8 代表 2024 年基线);BCD:半年度版本(B)及补丁号(C、D)。作用:定义数据库功能特性(如分布式事务、存储引擎优化)和安全更新。内核引擎版本(Kernel Engine Version)指 数据库底层执行引擎的精确版本,格式为 505.2.0.SPC0100,由主版本(505)、次版本(2)、补丁(0)及定制标签(SPCXXX)组成。作用:控制 SQL 解析、查询优化、事务处理等核心行为,直接影响性能与稳定性。 2. 他们几个“好朋友”之间的层级关系三者呈 自上而下的依赖链:GaussDB 产品版本 → 数据库引擎版本 → 内核引擎版本产品版本 决定可选的 数据库引擎版本(如产品版本 24.7.30.10对应引擎 V2.0-8.202.0);数据库引擎版本 绑定特定 内核引擎版本(如引擎 V2.0-8.202.0对应内核 505.2.0.SPC0100)。⚠️ 关键约束:升级产品版本(如从 24.1.30到 24.7.30.10)可能同步更新引擎和内核;但引擎或内核的独立升级需严格遵循版本兼容性矩阵。 3. 区别对比维度GaussDB 版本号数据库引擎版本内核引擎版本定位产品全栈发布标识数据库服务功能基线底层执行引擎实现格式24.7.30.10V2.0-A.BCD505.2.0.SPCXXX变更频率中(季度/年度)中高(半年度/补丁)高(月度/热修复)影响范围全组件(API/控制台/引擎)数据库功能与兼容性查询性能、事务逻辑查看位置云服务控制台公告实例“基本信息”页实例“基本信息”页 4. 实际应用中的关联版本升级路径用户需先确认当前 产品版本 支持的引擎版本列表,再选择目标引擎版本对应的内核版本。例如:产品版本 24.7.30.10(华为云 Stack 8.5.0)允许升级至引擎 V2.0-8.202.0,内核同步更新为 505.2.0.SPC0100。问题诊断与兼容性内核版本用于定位 SQL 执行层 Bug(如查询优化器缺陷);数据库引擎版本决定是否支持特定功能(如透明数据加密);产品版本影响 API 接口和运维工具兼容性。生命周期管理华为云会公布每个 产品版本 的 EOM(停售)、EOFS(停止支持)、EOS(终止服务)时间,用户需据此规划升级。例如 V2.0-8.201引擎版本的 EOFS 时间为 2028 年 12 月,到期后将不再提供安全补丁。 5. 如何查看版本信息控制台查看:登录华为云 ManageOne → 进入 GaussDB 实例列表 → 选择目标实例 → 在“基本信息”页面的 “数据库信息”模块 直接查看:数据库引擎版本(如 V2.0-8.202.0)内核引擎版本(如 505.2.0.SPC0100)。API 查询:调用 查询数据库引擎的版本和 查询数据库引擎内核版本接口获取版本列表。 总结一下下GaussDB 版本号 = 产品发布包标识;数据库引擎版本 = 数据库功能基线;内核引擎版本 = 执行引擎实现细节;三者关系:产品版本选择决定可用引擎版本,引擎版本绑定内核版本。运维时需以产品版本生命周期为纲,以引擎功能为目,以内核性能为根,协同管理。
-
我的第一个云上应用:基于华为云开发者空间和GaussDB的极简留言墙**一、 案例简介 **1.1 项目概述本文完整记录了我在华为云开发者空间上,利用其提供的云开发环境和GaussDB数据库,从零开始构建并部署一个Web留言墙应用的全部过程。这是一个非常适合新手的入门项目,可以快速体验到云上开发的全流程。1.2 技术选型云开发环境: 华为云开发者空间 (HCE 2.0),作为本次开发和部署的服务器。后端技术: Node.js + Express 框架,这是一种轻量且高效的JavaScript后端技术栈。数据库: 华为云开发者空间生态版GaussDB,用于存储我们的留言数据。前端技术: 原生 HTML + JavaScript,无需复杂框架,专注于核心功能。二、 准备工作2.1 领取云资源根据官方活动指引,我首先进入了华为云开发者空间控制台,成功领取了本次实践所需的“云开发环境”和“生态版GaussDB”资源。2.2 获取GaussDB连接信息为了让我们的应用能连接到数据库,我点击进入GaussDB实例详情页面,找到了关键的连接信息,并记录了下来。内网地址: [ 请在此处填写您自己的内网IP地址,例如: 192.168.0.29 ]端口: [ 请在此处填写您自己的数据库端口,例如: 8000 ]用户名: [ 请在此处填写您的数据库用户名,例如: root ]密码: (创建时设置的密码)**三、 项目开发与部署 **3.1 准备数据库表在开始写代码前,我先使用华为云的DAS(数据管理服务)工具为我的留言墙应用创建了一张数据表。在GaussDB实例列表页,我点击“登录”进入DAS。然后进入“SQL查询”窗口,执行了下面的SQL语句来创建messages表。【代码块】SQLCREATE TABLE messages ( id VARCHAR(36) PRIMARY KEY, username VARCHAR(50) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); 3.2 初始化后端项目接下来,我登录到云开发环境的终端,开始准备后端项目。创建一个项目目录并进入。【代码块】Bashmkdir my-guestbook cd my-guestbook初始化Node.js项目并安装必要的依赖库:express (Web框架), pg (GaussDB驱动), uuid (生成唯一ID), cors (处理跨域)。【代码块】Bashnpm init -y npm install express pg uuid cors3.3 编写后端代码我在项目目录下创建了一个 server.js 文件,并写入了下面全部的后端逻辑。【代码块】JavaScript// 引入依赖 const express = require('express'); const cors = require('cors'); const { Pool } = require('pg'); const { v4: uuidv4 } = require('uuid'); // 创建Express应用 const app = express(); app.use(cors()); // 允许跨域 app.use(express.json()); // 解析JSON请求体 app.use(express.static('public')); // 托管静态文件 // --- 数据库连接配置 --- // !!! 请将这里的配置信息替换为您自己的真实信息 !!! const pool = new Pool({ user: '[ 请在此处填写您的数据库用户名,例如: root ]', host: '[ 请在此处填写您自己的内网IP地址 ]', database: 'postgres', // 通常默认为postgres password: '[ 请在此处填写您自己的数据库密码 ]', port: [ 请在此处填写您的数据库端口,例如: 8000 ], }); // --- API 路由 --- // 获取所有留言 app.get('/api/messages', async (req, res) => { try { const client = await pool.connect(); const result = await client.query('SELECT * FROM messages ORDER BY created_at DESC'); res.json(result.rows); client.release(); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // 添加一条新留言 app.post('/api/messages', async (req, res) => { try { const { username, content } = req.body; const newId = uuidv4(); const client = await pool.connect(); const sql = 'INSERT INTO messages (id, username, content) VALUES ($1, $2, $3)'; await client.query(sql, [newId, username, content]); res.status(201).send('Message added'); client.release(); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // --- 启动服务器 --- const PORT = 8082; // 使用您云开发环境开放的端口 app.listen(PORT, () => { console.log(`服务器已在 http://localhost:${PORT} 启动`); }); 3.4 编写前端页面为了让用户能和我们的应用交互,我创建了一个 public 文件夹,并在里面创建了一个 index.html 文件。【代码块】HTML<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>云开发留言墙</title> <style> body { font-family: sans-serif; max-width: 600px; margin: auto; padding: 20px; } .form-container { background: #f4f4f4; padding: 15px; border-radius: 5px; margin-bottom: 20px; } .message { border: 1px solid #ccc; padding: 10px; margin-top: 10px; border-radius: 5px; } .message-user { font-weight: bold; } .message-time { font-size: 0.8em; color: #666; } </style> </head> <body> <h1>我的云上留言墙</h1> <div class="form-container"> <input type="text" id="username" placeholder="你的昵称"> <br><br> <textarea id="content" placeholder="说点什么..." rows="4" style="width: 98%;"></textarea> <br><br> <button onclick="postMessage()">发表留言</button> </div> <div id="message-board"></div> <script> const apiUrl = '/api/messages'; // 加载留言 async function loadMessages() { const response = await fetch(apiUrl); const messages = await response.json(); const board = document.getElementById('message-board'); board.innerHTML = ''; for (const msg of messages) { const div = document.createElement('div'); div.className = 'message'; const time = new Date(msg.created_at).toLocaleString(); div.innerHTML = `<div class="message-user">${msg.username}</div><p>${msg.content}</p><div class="message-time">${time}</div>`; board.appendChild(div); } } // 发表留言 async function postMessage() { const username = document.getElementById('username').value; const content = document.getElementById('content').value; await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, content }) }); document.getElementById('content').value = ''; // 清空输入框 loadMessages(); // 重新加载留言 } // 页面首次加载 window.onload = loadMessages; </script> </body> </html> 3.5 启动并测试应用万事俱备,我在云开发环境终端的项目根目录下,执行命令启动了我的Web应用。【代码块】Bashnode server.js**四、 最终成果展示应用成功启动后,我通过浏览器访问我的云开发环境公网IP和对应的端口,看到了我的留言墙应用界面。我成功地发表了一条留言,并且留言被正确地显示了出来,这证明我的应用已经完成了端到端构建,前后端与数据库均已成功打通!五、 总结通过本次实践,我成功地在华为云开发者空间上,独立完成了一个Web应用的开发和部署。整个过程非常顺畅,让我对云上开发、Node.js后端以及GaussDB数据库的使用有了更深入的认识。这是一个非常有价值的入门体验。
-
我的第一个云上应用:基于华为云开发者空间和GaussDB的极简留言墙**一、 案例简介 **1.1 项目概述本文完整记录了我在华为云开发者空间上,利用其提供的云开发环境和GaussDB数据库,从零开始构建并部署一个Web留言墙应用的全部过程。这是一个非常适合新手的入门项目,可以快速体验到云上开发的全流程。1.2 技术选型云开发环境: 华为云开发者空间 (HCE 2.0),作为本次开发和部署的服务器。后端技术: Node.js + Express 框架,这是一种轻量且高效的JavaScript后端技术栈。数据库: 华为云开发者空间生态版GaussDB,用于存储我们的留言数据。前端技术: 原生 HTML + JavaScript,无需复杂框架,专注于核心功能。二、 准备工作 (对应规则2)2.1 领取云资源根据官方活动指引,我首先进入了华为云开发者空间控制台,成功领取了本次实践所需的“云开发环境”和“生态版GaussDB”资源。2.2 获取GaussDB连接信息为了让我们的应用能连接到数据库,我点击进入GaussDB实例详情页面,找到了关键的连接信息,并记录了下来。内网地址: [ 请在此处填写您自己的内网IP地址,例如: 192.168.0.29 ]端口: [ 请在此处填写您自己的数据库端口,例如: 8000 ]用户名: [ 请在此处填写您的数据库用户名,例如: root ]密码: (创建时设置的密码)**三、 项目开发与部署 **3.1 准备数据库表在开始写代码前,我先使用华为云的DAS(数据管理服务)工具为我的留言墙应用创建了一张数据表。在GaussDB实例列表页,我点击“登录”进入DAS。然后进入“SQL查询”窗口,执行了下面的SQL语句来创建messages表。【代码块】SQLCREATE TABLE messages ( id VARCHAR(36) PRIMARY KEY, username VARCHAR(50) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); 3.2 初始化后端项目接下来,我登录到云开发环境的终端,开始准备后端项目。创建一个项目目录并进入。【代码块】Bashmkdir my-guestbook cd my-guestbook初始化Node.js项目并安装必要的依赖库:express (Web框架), pg (GaussDB驱动), uuid (生成唯一ID), cors (处理跨域)。【代码块】Bashnpm init -y npm install express pg uuid cors3.3 编写后端代码我在项目目录下创建了一个 server.js 文件,并写入了下面全部的后端逻辑。【代码块】JavaScript// 引入依赖 const express = require('express'); const cors = require('cors'); const { Pool } = require('pg'); const { v4: uuidv4 } = require('uuid'); // 创建Express应用 const app = express(); app.use(cors()); // 允许跨域 app.use(express.json()); // 解析JSON请求体 app.use(express.static('public')); // 托管静态文件 // --- 数据库连接配置 --- // !!! 请将这里的配置信息替换为您自己的真实信息 !!! const pool = new Pool({ user: '[ 请在此处填写您的数据库用户名,例如: root ]', host: '[ 请在此处填写您自己的内网IP地址 ]', database: 'postgres', // 通常默认为postgres password: '[ 请在此处填写您自己的数据库密码 ]', port: [ 请在此处填写您的数据库端口,例如: 8000 ], }); // --- API 路由 --- // 获取所有留言 app.get('/api/messages', async (req, res) => { try { const client = await pool.connect(); const result = await client.query('SELECT * FROM messages ORDER BY created_at DESC'); res.json(result.rows); client.release(); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // 添加一条新留言 app.post('/api/messages', async (req, res) => { try { const { username, content } = req.body; const newId = uuidv4(); const client = await pool.connect(); const sql = 'INSERT INTO messages (id, username, content) VALUES ($1, $2, $3)'; await client.query(sql, [newId, username, content]); res.status(201).send('Message added'); client.release(); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // --- 启动服务器 --- const PORT = 8082; // 使用您云开发环境开放的端口 app.listen(PORT, () => { console.log(`服务器已在 http://localhost:${PORT} 启动`); }); 3.4 编写前端页面为了让用户能和我们的应用交互,我创建了一个 public 文件夹,并在里面创建了一个 index.html 文件。【代码块】HTML<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>云开发留言墙</title> <style> body { font-family: sans-serif; max-width: 600px; margin: auto; padding: 20px; } .form-container { background: #f4f4f4; padding: 15px; border-radius: 5px; margin-bottom: 20px; } .message { border: 1px solid #ccc; padding: 10px; margin-top: 10px; border-radius: 5px; } .message-user { font-weight: bold; } .message-time { font-size: 0.8em; color: #666; } </style> </head> <body> <h1>我的云上留言墙</h1> <div class="form-container"> <input type="text" id="username" placeholder="你的昵称"> <br><br> <textarea id="content" placeholder="说点什么..." rows="4" style="width: 98%;"></textarea> <br><br> <button onclick="postMessage()">发表留言</button> </div> <div id="message-board"></div> <script> const apiUrl = '/api/messages'; // 加载留言 async function loadMessages() { const response = await fetch(apiUrl); const messages = await response.json(); const board = document.getElementById('message-board'); board.innerHTML = ''; for (const msg of messages) { const div = document.createElement('div'); div.className = 'message'; const time = new Date(msg.created_at).toLocaleString(); div.innerHTML = `<div class="message-user">${msg.username}</div><p>${msg.content}</p><div class="message-time">${time}</div>`; board.appendChild(div); } } // 发表留言 async function postMessage() { const username = document.getElementById('username').value; const content = document.getElementById('content').value; await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, content }) }); document.getElementById('content').value = ''; // 清空输入框 loadMessages(); // 重新加载留言 } // 页面首次加载 window.onload = loadMessages; </script> </body> </html> 3.5 启动并测试应用万事俱备,我在云开发环境终端的项目根目录下,执行命令启动了我的Web应用。【代码块】Bashnode server.js四、 最终成果展示应用成功启动后,我通过浏览器访问我的云开发环境公网IP和对应的端口,看到了我的留言墙应用界面。我成功地发表了一条留言,并且留言被正确地显示了出来,这证明我的应用已经完成了端到端构建,前后端与数据库均已成功打通!五、 总结通过本次实践,我成功地在华为云开发者空间上,独立完成了一个Web应用的开发和部署。整个过程非常顺畅,让我对云上开发、Node.js后端以及GaussDB数据库的使用有了更深入的认识。这是一个非常有价值的入门体验。我正在参加【案例共创】第6期 开发者空间-基于云开发环境和GaussDB构建应用 https://bbs.huaweicloud.com/forum/thread-0229189398343651003-1-1.html
-
我的第一个云上应用:基于华为云开发者空间和GaussDB的极简留言墙**一、 案例简介 **1.1 项目概述本文完整记录了我在华为云开发者空间上,利用其提供的云开发环境和GaussDB数据库,从零开始构建并部署一个Web留言墙应用的全部过程。这是一个非常适合新手的入门项目,可以快速体验到云上开发的全流程。1.2 技术选型云开发环境: 华为云开发者空间 (HCE 2.0),作为本次开发和部署的服务器。后端技术: Node.js + Express 框架,这是一种轻量且高效的JavaScript后端技术栈。数据库: 华为云开发者空间生态版GaussDB,用于存储我们的留言数据。前端技术: 原生 HTML + JavaScript,无需复杂框架,专注于核心功能。二、 准备工作 (对应规则2)2.1 领取云资源根据官方活动指引,我首先进入了华为云开发者空间控制台,成功领取了本次实践所需的“云开发环境”和“生态版GaussDB”资源。2.2 获取GaussDB连接信息为了让我们的应用能连接到数据库,我点击进入GaussDB实例详情页面,找到了关键的连接信息,并记录了下来。内网地址: [ 请在此处填写您自己的内网IP地址,例如: 192.168.0.29 ]端口: [ 请在此处填写您自己的数据库端口,例如: 8000 ]用户名: [ 请在此处填写您的数据库用户名,例如: root ]密码: (创建时设置的密码)**三、 项目开发与部署 **3.1 准备数据库表在开始写代码前,我先使用华为云的DAS(数据管理服务)工具为我的留言墙应用创建了一张数据表。在GaussDB实例列表页,我点击“登录”进入DAS。然后进入“SQL查询”窗口,执行了下面的SQL语句来创建messages表。【代码块】SQLCREATE TABLE messages ( id VARCHAR(36) PRIMARY KEY, username VARCHAR(50) NOT NULL, content TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP ); 3.2 初始化后端项目接下来,我登录到云开发环境的终端,开始准备后端项目。创建一个项目目录并进入。【代码块】Bashmkdir my-guestbook cd my-guestbook初始化Node.js项目并安装必要的依赖库:express (Web框架), pg (GaussDB驱动), uuid (生成唯一ID), cors (处理跨域)。【代码块】Bashnpm init -y npm install express pg uuid cors3.3 编写后端代码我在项目目录下创建了一个 server.js 文件,并写入了下面全部的后端逻辑。【代码块】JavaScript// 引入依赖 const express = require('express'); const cors = require('cors'); const { Pool } = require('pg'); const { v4: uuidv4 } = require('uuid'); // 创建Express应用 const app = express(); app.use(cors()); // 允许跨域 app.use(express.json()); // 解析JSON请求体 app.use(express.static('public')); // 托管静态文件 // --- 数据库连接配置 --- // !!! 请将这里的配置信息替换为您自己的真实信息 !!! const pool = new Pool({ user: '[ 请在此处填写您的数据库用户名,例如: root ]', host: '[ 请在此处填写您自己的内网IP地址 ]', database: 'postgres', // 通常默认为postgres password: '[ 请在此处填写您自己的数据库密码 ]', port: [ 请在此处填写您的数据库端口,例如: 8000 ], }); // --- API 路由 --- // 获取所有留言 app.get('/api/messages', async (req, res) => { try { const client = await pool.connect(); const result = await client.query('SELECT * FROM messages ORDER BY created_at DESC'); res.json(result.rows); client.release(); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // 添加一条新留言 app.post('/api/messages', async (req, res) => { try { const { username, content } = req.body; const newId = uuidv4(); const client = await pool.connect(); const sql = 'INSERT INTO messages (id, username, content) VALUES ($1, $2, $3)'; await client.query(sql, [newId, username, content]); res.status(201).send('Message added'); client.release(); } catch (err) { console.error(err); res.status(500).send('Server Error'); } }); // --- 启动服务器 --- const PORT = 8082; // 使用您云开发环境开放的端口 app.listen(PORT, () => { console.log(`服务器已在 http://localhost:${PORT} 启动`); }); 3.4 编写前端页面为了让用户能和我们的应用交互,我创建了一个 public 文件夹,并在里面创建了一个 index.html 文件。【代码块】HTML<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>云开发留言墙</title> <style> body { font-family: sans-serif; max-width: 600px; margin: auto; padding: 20px; } .form-container { background: #f4f4f4; padding: 15px; border-radius: 5px; margin-bottom: 20px; } .message { border: 1px solid #ccc; padding: 10px; margin-top: 10px; border-radius: 5px; } .message-user { font-weight: bold; } .message-time { font-size: 0.8em; color: #666; } </style> </head> <body> <h1>我的云上留言墙</h1> <div class="form-container"> <input type="text" id="username" placeholder="你的昵称"> <br><br> <textarea id="content" placeholder="说点什么..." rows="4" style="width: 98%;"></textarea> <br><br> <button onclick="postMessage()">发表留言</button> </div> <div id="message-board"></div> <script> const apiUrl = '/api/messages'; // 加载留言 async function loadMessages() { const response = await fetch(apiUrl); const messages = await response.json(); const board = document.getElementById('message-board'); board.innerHTML = ''; for (const msg of messages) { const div = document.createElement('div'); div.className = 'message'; const time = new Date(msg.created_at).toLocaleString(); div.innerHTML = `<div class="message-user">${msg.username}</div><p>${msg.content}</p><div class="message-time">${time}</div>`; board.appendChild(div); } } // 发表留言 async function postMessage() { const username = document.getElementById('username').value; const content = document.getElementById('content').value; await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, content }) }); document.getElementById('content').value = ''; // 清空输入框 loadMessages(); // 重新加载留言 } // 页面首次加载 window.onload = loadMessages; </script> </body> </html> 3.5 启动并测试应用万事俱备,我在云开发环境终端的项目根目录下,执行命令启动了我的Web应用。【代码块】Bashnode server.js四、 最终成果展示应用成功启动后,我通过浏览器访问我的云开发环境公网IP和对应的端口,看到了我的留言墙应用界面。我成功地发表了一条留言,并且留言被正确地显示了出来,这证明我的应用已经完成了端到端构建,前后端与数据库均已成功打通!五、 总结通过本次实践,我成功地在华为云开发者空间上,独立完成了一个Web应用的开发和部署。整个过程非常顺畅,让我对云上开发、Node.js后端以及GaussDB数据库的使用有了更深入的认识。这是一个非常有价值的入门体验。我正在参加【案例共创】第6期 开发者空间-基于云开发环境和GaussDB构建应用 https://bbs.huaweicloud.com/forum/thread-0229189398343651003-1-1.html
-
第一次使用GaussDB的B模式,发现不支持函数IFNULl(),官方文档是支持的,是什么原因呢,有啥排查思路,请各位大佬帮忙看看~数据库版本:GaussDB Kernel 503.1.0.SPC2700 build 7eba2998
-
GaussDB 兼容 Activiti 5.14 需要从数据库兼容性配置、Activiti 配置调整、SQL 语法适配等方面入手,核心是让 Activiti 5.14 的数据库操作(表结构初始化、CRUD、事务等)能在 GaussDB 上正常运行。 一、前提:确认 GaussDB 的兼容性模式Activiti 5.14 原生支持 PostgreSQL、MySQL 等主流数据库,而 GaussDB(尤其是 GaussDB 100/200)通常兼容 PostgreSQL 协议和语法。建议把GaussDB 配置为PostgreSQL 兼容模式(默认可能已开启,可以去通过show server_version;确认兼容的 PostgreSQL 版本),为 Activiti 提供基础兼容性。 二、核心配置步骤1. 调整 Activiti 5.14 的数据库连接配置Activiti 通过activiti.cfg.xml(或 Spring 配置)指定数据库连接信息,需修改为 GaussDB 的连接参数: 替换 JDBC 驱动:使用 GaussDB 的 JDBC 驱动(如com.huawei.gauss200.jdbc.Driver,需根据 GaussDB 版本下载对应驱动包,放入项目依赖)。修改连接串:按 GaussDB 的 JDBC 格式配置(参考之前的连接串配置)。指定数据库类型:告知 Activiti 使用 PostgreSQL 的适配策略(因 GaussDB 兼容 PostgreSQL)。 修改一下activiti.cfg.xml文件 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <!-- 数据库连接配置 --> <property name="jdbcUrl" value="jdbc:gaussdb://192.168.1.100:8000/activiti_db?currentSchema=activiti" /> <property name="jdbcDriver" value="com.huawei.gauss200.jdbc.Driver" /> <property name="jdbcUsername" value="username" /> <property name="jdbcPassword" value="password" /> <!-- 数据库类型:指定为postgresql(GaussDB兼容PostgreSQL) --> <property name="databaseType" value="postgresql" /> <!-- 初始化策略:自动创建表结构(首次运行时) --> <property name="databaseSchemaUpdate" value="true" /> <!-- 其他配置(如事务、连接池等) --> <property name="transactionManager" ref="transactionManager" /></bean> 2. 适配 Activiti 的表结构初始化语句Activiti 5.14 启动时会自动创建一系列表(如ACT_RE_PROCDEF、ACT_RU_EXECUTION等)自增主键:Activiti 对 PostgreSQL 使用SERIAL类型作为自增主键,GaussDB 兼容SERIAL(本质是integer+ 自增序列),通常无需修改;若出现问题,可替换为BIGSERIAL(对应bigint)。字符集与排序规则:GaussDB 默认字符集可能为UTF8,需确保与 Activiti 表的字符集一致,可在建表时指定ENCODING 'UTF8'。约束与索引:GaussDB 对某些约束(如外键、唯一索引)的语法可能略有差异,若初始化失败,需提取 Activiti 的建表脚本(可从activiti-engine-x.x.x.jar的org/activiti/db/create目录中找到postgresql脚本),手动修改后在 GaussDB 中执行。 比如:调整后的建表语句(我以 ACT_RE_DEPLOYMENT 为例): CREATE TABLE ACT_RE_DEPLOYMENT ( ID_ VARCHAR(64) NOT NULL, NAME_ VARCHAR(255), DEPLOY_TIME_ TIMESTAMP, PRIMARY KEY (ID_)) WITH (ORIENTATION = ROW, COMPRESSION = NO); -- GaussDB的表存储参数 3. 处理 SQL 语法与函数差异Activiti 5.14 的内部 SQL 操作可能依赖 PostgreSQL 的特定函数(如日期函数、字符串处理函数),若 GaussDB 存在兼容差异,需针对性修改: 日期函数:例如 PostgreSQL 的NOW()在 GaussDB 中可直接使用(兼容);若涉及DATE_PART等函数,GaussDB 通常也支持,无需修改。字符串函数:如SUBSTRING、CONCAT等函数在 GaussDB 中与 PostgreSQL 兼容,一般无需调整。分页语法:Activiti 使用LIMIT ? OFFSET ?进行分页,GaussDB 完全支持该语法,无需修改。 若出现特定 SQL 报错,可通过以下方式解决: 开启 Activiti 的 SQL 日志(<property name="jpaHandleTransaction" value="true" /> + 日志级别DEBUG),定位报错 SQL。自定义 Activiti 的SqlSession,替换兼容 GaussDB 的 SQL 语句(需继承org.activiti.engine.impl.db.DbSqlSession并重写对应方法)。4. 事务与连接池适配事务隔离级别:GaussDB 支持常见的事务隔离级别(如READ COMMITTED),与 Activiti 默认要求一致,无需额外配置。连接池配置:若使用 Druid、Hikari 等连接池,需确保连接池参数适配 GaussDB(如maxPoolSize、idleTimeout),避免连接超时或资源耗尽。 比如(Druid 连接池配置): <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="url" value="jdbc:gaussdb://192.168.1.100:8000/activiti_db" /> <property name="driverClassName" value="com.huawei.gauss200.jdbc.Driver" /> <property name="username" value="username" /> <property name="password" value="password" /> <property name="maxActive" value="20" /> <property name="minIdle" value="5" /> <property name="validationQuery" value="SELECT 1" /> <!-- GaussDB支持的验证语句 --></bean> 三、测试和验证一下表结构初始化:启动 Activiti 引擎,检查是否成功创建所有表(共 23 张左右,前缀为ACT_)。流程部署:部署一个简单的 BPMN 流程,验证ACT_RE_PROCDEF、ACT_GE_BYTEARRAY等表是否正确插入数据。流程运行:启动流程实例,检查ACT_RU_EXECUTION、ACT_RU_TASK等运行时表是否正常记录数据,任务完成后是否正确更新到历史表(ACT_HI_*)。异常场景:模拟流程中断、并发操作,验证事务回滚和数据一致性是否正常。 四、常见的问题和一些简单的解决方法推荐问题 1:如果表创建失败,提示 “不支持的类型 SERIAL”解决:将建表语句中的SERIAL替换为BIGINT+ 手动创建序列(如CREATE SEQUENCE ACT_GE_PROPERTY_SEQ START WITH 1 INCREMENT BY 1),并在插入时使用nextval('序列名')。问题 2:如果SQL 报错 “函数 xxx 不存在”解决:确认 GaussDB 是否支持该函数,若不支持,修改 Activiti 的 SQL 脚本,替换为 GaussDB 兼容的函数(如用SUBSTR替代SUBSTRING,视具体情况而定)。问题 3:如果连接超时或频繁断开解决:调整 GaussDB 的idle_in_transaction_session_timeout参数,或在连接池配置中增加validationQuery定期验证连接。 总结一下下GaussDB 兼容 Activiti 5.14 的核心是利用其 PostgreSQL 兼容性,通过调整连接配置、适配表结构和 SQL 语法,确保 Activiti 的数据库操作在 GaussDB 上正常执行。实际操作中需结合具体报错信息逐步调试,重点关注表初始化、SQL 函数和事务处理三个环节。
-
求助各位大佬,第一次使用gaussDB数据库的mysql兼容模式B模式,发现不支持函数IFNULl(),但是看官方文档是支持的
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签