openGauss实验全链路:从安装gsql到JDBC连接数据库
简介《郑州大学数据库实验报告书》是一份面向计算机科学与技术、软件工程专业学生的数据库实验课程完整报告内含九个递进式实验认识DBMS、创建数据库表与索引、交互式SQL、创建视图、完整性控制、安全性控制、事务与并发控制、数据库备份与恢复、JDBC连接数据库覆盖openGauss平台下数据库原理核心实践环节。资源包共1个docx文件约3.23MB排版规范每项实验均说明实验目的、仪器材料、操作步骤、结果分析及遇到的问题与更正思路并配有编号图题与截图适合作为课程报告参考或期末复习材料。目前已有1522人学习浏览反映出其作为实验指南与报告模板的实用价值。通过这份报告读者既能对照openGauss完成从环境搭建、gsql连接到权限分配、完整性约束设置、事务隔离与锁机制、数据备份恢复再到JDBC编程的完整训练也能借鉴其规范的实验记录方式提升分析问题和解决实际问题的能力为后续数据库应用开发或课程考核提供完整参考。1. 数据库实验报告资源拆解从 openGauss 安装跑到 JDBC 连接的完整链路如果你正在被数据库原理的实验报告困住不知道从哪台虚拟机开始或者照着文档敲完 gsql 却卡在连接不上这份九实验报告书值得花一个下午拆开看。它不堆概念把认识 DBMS、建库建表、交互式 SQL、视图、完整性、安全性、事务并发、备份恢复、JDBC 连接九个环节串成完整链路每个实验都给了可复现的命令和表结构甚至有教师表、学生表、选课表的建表语句。对刚入门数据库的新手它是照着敲就能出结果的实验手册对需要交报告的从业者它是理顺操作顺序和截图规范的参考模板。一句话这不是科普是一份能直接落地复现的数据库实验操作全集。2. 环境搭建openGauss 安装选型与 gsql 连接排雷2.1 三种安装方式怎么选先说结论再给理由实验一的核心是搭建 openGauss 环境原文列出了三种安装模式云服务器安装、虚拟机一键安装、在 openEuler 系统上手动安装。我实际跑下来虚拟机和云服务器完全不是一回事。安装方式前置条件耗时适合场景云服务器安装需要一台云主机内存 4GB 以上30-60 分钟多人协作、需要外网访问虚拟机一键安装VMware/VirtualBox 导入镜像即可15-30 分钟单机学习、交实验报告openEuler 手动安装Linux 基础操作熟练60-120 分钟想理解安装细节、排查依赖我一般建议做实验选虚拟机一键安装理由很简单openGauss 的依赖项多手动装大概率栽在 glibc 版本和 Python 环境上一键镜像把这些都预装好了。唯一要注意的是虚拟机内存openGauss 对资源不算客气4GB 内存是底线低于这个数启动时会报 shared memory 不足那个报错很容易劝退新手。无论哪种方式装完的第一件事不是急着建表而是确认数据库服务已经起来再考虑 gsql 客户端怎么连。gsql 是 openGauss 自带的命令行工具后面所有实验都靠它执行。2.2 启动服务与 gsql 连接三个命令里藏着三个常犯的错连接数据库的完整过程分为两步启动服务、用 gsql 登录。先看启动部分# 切换到 openGauss 安装用户默认是 omm su - omm # 启动数据库服务 gs_om -t start # 连接默认数据库 postgres gsql -d postgres -p 26000 -r逻辑说明su - omm必须用-参数它表示同时切换环境变量否则后面 gs_om 命令很可能提示命令找不到gs_om -t start里的-t指定操作类型为 start还有stop和status两个常用取值gsql的-d指定数据库名-p是端口-r是开启 Readline 功能支持方向键回看历史命令少了这个参数在终端里输错一个长 SQL 就得重敲非常难受。这里有三个新手高频翻车点我直接列出来端口不对。openGauss 默认端口是 26000不是 PostgreSQL 的 5432这是最容易踩的坑很多人拿 pg 的习惯去连必然报连接失败。用户不对。刚装完只有 omm 这个管理员用户能连接不是 root 也不是自己新建的操作系统用户登录时没带用户名默认走当前系统用户。-r和-d的位置写反。gsql -p 26000 -d postgres -r和gsql -d postgres -p 26000 -r都合法但如果把-r写在-d postgres前面后面的postgres会被当成要执行的 SQL 语句报 syntax error这是很隐蔽的视觉盲区。连接成功后看到的提示符是postgres#这里的#表示当前是超级用户。2.3 gsql 元命令与系统表同一件事的两种查法gsql 里有一批以反斜杠开头的元命令它们是快速查看数据库对象的入口。下面是一份实际实验中最常用的命令表命令作用等价 SQL 写法\l列出所有数据库SELECT datname FROM pg_database;\dt列出当前库所有表SELECT tablename FROM pg_tables;\d tablename查看表的属性和结构\d系列命令\dn列出所有 schema查 pg_namespace\di列出所有索引查 pg_indexes\db查询表空间SELECT spcname FROM pg_tablespace;\c dbname切换数据库无\q退出 gsql无-- 查看数据库列表 SELECT datname FROM pg_database; -- 查看表空间列表 SELECT spcname FROM pg_tablespace; -- 查看用户列表 SELECT * FROM pg_user; -- 查看所有角色 SELECT * FROM pg_roles;逻辑说明pg_database、pg_tablespace、pg_user、pg_roles都是系统表openGauss 沿用 PostgreSQL 的 catalog 设计数据字典存在这些系统表里。pg_user查出来的是实打实的登录账号pg_roles查的是角色两者通过pg_auth_members关联。参数说明\d比\d多返回列的注释和存储统计信息实验报告里要求截图展示表结构我建议统一用\d截图内容更完整老师看了也不用追问。这里的辨识度很重要用户是具体某个人角色是一组权限的集合。我在实验报告里写过一个仓库管理员比喻数据库里给张三分配仓库管理员角色张三就自动获得该角色下所有表权限这样新员工入职只需要换角色不用一条条 GRANT这个例子直接写在报告里就是很完整的辨析题素材。3. 建库建表与索引表空间、Schema 和约束的正确打开方式3.1 创建表空间与数据库先用目录思维理解再敲命令实验二第一步是创建表空间和数据库原文给了一段创建表空间的语句。这里要分清三个概念表空间是磁盘上的一块存储目录数据库是逻辑上的数据集合一张表最终落盘在某表空间的物理文件里。-- 创建表空间relative location 指向数据目录下的相对路径 CREATE TABLESPACE tpcds_local RELATIVE LOCATION tablespace/tablespace_1; -- 创建数据库并指定表空间 CREATE DATABASE db_sc WITH TABLESPACE tpcds_local; -- 数据库改名 ALTER DATABASE db_sc RENAME TO db_school; -- 切换数据库 \c db_school逻辑说明RELATIVE LOCATION用的是相对路径openGauss 会在数据目录下自动拼出完整路径这里不需要手工创建目录写绝对路径反而容易因为权限问题报错。WITH TABLESPACE把数据库的默认表空间指向我们刚建的 tpcds_local以后在这个数据库里建表默认都放在这个表空间下。参数说明CREATE TABLESPACE的名字可以自定义但位置路径最好用项目名相关多个实验共用一台虚拟机时靠表空间名字就能区分哪个库占哪块盘避免后面备份恢复时找错路径。常见做法是创建数据库后立即\c切过去再继续建表如果不切换后面所有表都会建在 postgres 库里实验报告截图里全是 postgres 前缀给答辩埋雷。3.2 创建 Schema 与表先理解“模式”是命名空间原文对 Schema 的解释偏教材化我把它翻译成大白话Schema 相当于一个命名空间里面装表、视图、存储过程这些对象。不同 Schema 下可以存在同名表互不干扰。-- 创建模式 CREATE SCHEMA book_eg; -- 在模式中创建教师信息表 CREATE TABLE book_eg.Teachers( Tno CHAR(20) PRIMARY KEY, Tname CHAR(20) NOT NULL, Sex CHAR(20) CHECK(Sex 男 OR Sex 女), Birthday DATE, Title CHAR(20), Dno CHAR(20) ); -- 创建院系信息表外键关联教师表主键 CREATE TABLE book_eg.Departments( Dno CHAR(20) PRIMARY KEY, Dname CHAR(20), Dheadno CHAR(20), FOREIGN KEY (Dheadno) REFERENCES book_eg.Teachers(Tno) ); -- 级联删除整个模式及其全部对象 DROP SCHEMA book_eg CASCADE;逻辑说明CREATE TABLE book_eg.Teachers用点号限定表所属模式这与 SQL Server 的dbo.表名是同一个思路。CASCADE是级联删除把模式连带里面的表、视图、索引全删掉不加它会在模式非空时报错。这里要提醒一个建表顺序的问题Departments 表外键引用 Teachers.Tno所以必须先建 Teachers 再建 Departments否则 PostgreSQL 系的数据库会直接抛relation teachers does not exist。凡是表之间有互相引用的全部长这样处理先把不带外键的表建完再用 ALTER TABLE 补外键。3.3 列级约束与表级约束位置不同能力边界也不同约束这部分是实验报告里最容易失分的地方。列级约束写在列定义后面只能约束当前列表级约束写在所有列定义之后可以一次约束多列。-- 学生信息表主键和 CHECK 用列级约束外键用表级约束 CREATE TABLE book_eg.Students( Sno CHAR(20) PRIMARY KEY, Sname CHAR(20) NOT NULL, Sex CHAR(20) CHECK(Sex 男 OR Sex 女), Birthday DATE, Enrollyear CHAR(20), Speciality CHAR(20), Dno CHAR(20), FOREIGN KEY (Dno) REFERENCES book_eg.Departments(Dno) ); -- 课程信息表SMALLINT 取值范围有限适合学分和学时 CREATE TABLE book_eg.Courses( Cno CHAR(20) PRIMARY KEY, Cname CHAR(20) NOT NULL, Period SMALLINT, Credit SMALLINT );逻辑说明CHECK(Sex 男 OR Sex 女)防止脏数据这个约束本身不复杂但在实验报告里建议加一句“列级约束无法命名表级约束可以”这是两类约束最关键的能力差异。非空约束 NOT NULL 和默认值 DEFAULT 都只能写在列级表级约束栏写不了这两个这是面试和答辩高频追问点。Period SMALLINT和Credit SMALLINT是学分和学时用 SMALLINT 就够范围是 -32768 到 32767不会有人一学期修 3 万学时。这个细节写进报告可以体现对类型长度的理解比起全部用默认 INT 是加分项。3.4 修改表结构与索引ALTER TABLE 补外键CREATE INDEX 提速表之间有交叉引用时ALTER TABLE 是后悔药。比如 Teachers 和 Departments 互相引用可以先建 Teachers再建 Departments最后给 Teachers 补外键-- 给教师表补充外键引用院系表的 Dno ALTER TABLE book_eg.Teachers ADD CONSTRAINT fk_teacher_dept FOREIGN KEY (Dno) REFERENCES book_eg.Departments(Dno); -- 在 Students 表的 Dno 列上创建索引 CREATE INDEX Student_Dept ON book_eg.Students(Dno); -- 查看当前库所有索引 \di参数说明ADD CONSTRAINT后面给外键起名 fk_teacher_dept起名习惯用fk_表名_字段名格式后续要删除这个约束时DROP CONSTRAINT fk_teacher_dept就能准确命中不起名的话系统会自动生成一串随机字符排查问题时根本认不出谁是谁。索引那一行Student_Dept是索引名Students(Dno)表示对 Dno 列建索引。要注意 openGauss 建主键时会自动创建唯一索引所以PRIMARY KEY 的列不需要手工再建索引重复建会造成索引冗余写入性能白白受损这点实验报告里可以主动写一句能体现对索引原理的真正理解。4. 视图、完整性控制与安全性从 SQL 交互到多用户权限4.1 交互式 SQLDML 的常见形态与聚合查询实验三要求掌握交互式 SQL原文只列了标题我按数据库课程的标准路径补一组最常用语句这份报告里建的表可以直接套用。-- 插入一条学生记录 INSERT INTO book_eg.Students VALUES (20210001, 张三, 男, 2003-05-12, 2021, 计算机科学与技术, D01); -- 查询计算机专业学生名单 SELECT Sno, Sname FROM book_eg.Students WHERE Speciality 计算机科学与技术 ORDER BY Sno; -- 统计各专业学生人数 SELECT Speciality, COUNT(*) AS cnt FROM book_eg.Students GROUP BY Speciality HAVING COUNT(*) 1; -- 更新选课成绩先建 SC 表后使用 UPDATE book_eg.SC SET Grade 85 WHERE Sno 20210001 AND Cno C001;逻辑说明INSERT的 VALUES 顺序必须与表结构列顺序一致不一致时建议显式写列名GROUP BY配合HAVING做分组后过滤WHERE是分组前过滤两者的执行时机完全不同报告中最好把这条注释写清楚。UPDATE 不带 WHERE 会更新整张表这是最经典的翻车语句。4.2 创建视图把复杂查询包装成“虚拟表”实验四的视图是理解数据库抽象层次的关键。视图本身不存数据只存 SELECT 定义每次查询时动态执行。-- 创建视图学生及其院系名称 CREATE VIEW v_student_info AS SELECT s.Sno, s.Sname, d.Dname FROM book_eg.Students s JOIN book_eg.Departments d ON s.Dno d.Dno; -- 查看视图结果 SELECT * FROM v_student_info; -- 带检查选项的可更新视图 CREATE VIEW v_student_boy AS SELECT Sno, Sname FROM book_eg.Students WHERE Sex 男 WITH CHECK OPTION; -- 删除视图 DROP VIEW v_student_info;参数说明WITH CHECK OPTION很关键加了它之后通过视图插入或更新数据时数据库会校验新数据是否满足视图的 WHERE 条件不满足直接报错。没有这个选项你可以通过 v_student_boy 插入一条 Sex 女 的记录插入成功但下一条 SELECT 查不到这条数据这个“幽灵行”问题笔试经常考。视图不是万能的带GROUP BY、聚合函数、DISTINCT 的视图不可更新理由是视图与基表行之间无法建立一一映射。报告里写这个限制能体现对视图本质的理解而不是停留在“会 CREATE VIEW”。4.3 完整性控制约束不止建表时的那几个实验五的完整性控制比建表约束更进一步。除了 CHECK、NOT NULL、主外键还涉及断言和触发器。openGauss 支持触发器和规则触发器在实际工程项目里用得非常广。-- 示例更新教师职称时记录审计日志需要先建日志表 CREATE TABLE book_eg.TitleAudit( Tno CHAR(20), OldTitle CHAR(20), NewTitle CHAR(20), ChangeTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE OR REPLACE FUNCTION log_title_change() RETURNS TRIGGER AS $$ BEGIN INSERT INTO book_eg.TitleAudit(Tno, OldTitle, NewTitle) VALUES (OLD.Tno, OLD.Title, NEW.Title); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_title_audit AFTER UPDATE OF Title ON book_eg.Teachers FOR EACH ROW EXECUTE FUNCTION log_title_change();逻辑说明触发器包含三要素——触发时机 BEFORE/AFTER、触发事件 INSERT/UPDATE/DELETE、触发粒度行级或语句级。上面这个例子是行级 AFTER UPDATE 触发器只要 Title 字段被更新旧值和新值都会写入审计表。“完整性”在这里体现为应用层可以不守规矩但数据库层兜底记录所有变更。参数说明FOR EACH ROW是行级触发器每改一行执行一次函数。如果改成FOR EACH STATEMENT一次 UPDATE 影响 100 行只执行一次性能好但拿不到每一行的 OLD 和 NEW。审计需求必须用行级这是参数选择的依据。4.4 安全性控制GRANT 与 REVOKE 搭配角色实验六的安全性控制重点在权限分配。openGauss 的权限体系是用户-角色-权限三层结构。前面实验创建的 omm 是超级用户实验六要新建受限用户。-- 创建新用户 CREATE USER db_user1 PASSWORD User1234; -- 仅授予查询权限 GRANT SELECT ON book_eg.Students TO db_user1; -- 授予插入和更新权限 GRANT INSERT, UPDATE ON book_eg.Teachers TO db_user1; -- 回收权限 REVOKE UPDATE ON book_eg.Teachers FROM db_user1; -- 查看用户权限 SELECT * FROM information_schema.table_privileges WHERE grantee db_user1;逻辑说明GRANT SELECT只给了读权限这个用户能查 Students 但不能改REVOKE UPDATE回收更新权限操作粒度精确到命令级别。openGauss 对权限的控制比 MySQL 细很多可以精确到列-- 只允许查看学生姓名和学号两列 GRANT SELECT (Sno, Sname) ON book_eg.Students TO db_user1;这个列级权限是面试加分项真正在生产环境的权限设计里用得非常多默认所有列可查反而是隐患。报告中如果能对比“表级权限”和“列级权限”的差异安全实验的深度就出来了。5. 事务、并发与备份恢复数据安全相关的五个高频排查点5.1 事务控制语句COMMIT 之前一切可以反悔实验七围绕事务的 ACID 特性展开。openGauss 默认每个语句自动提交需要显式开启事务块才能把多条语句合成一个原子操作。-- 开启事务 BEGIN; -- 插入选课记录 INSERT INTO book_eg.SC(Sno, Cno, Grade) VALUES (20210001, C001, 90); -- 检查无误后提交 COMMIT; -- 如果发现插错回滚撤销 ROLLBACK;逻辑说明BEGIN之后的所有 DML 都处于未提交状态其他会话看不到这些改动这就是事务的隔离性。COMMIT是终局裁定一旦提交就无法回滚ROLLBACK是后悔药能把 BEGIN 之后所有操作全部撤销。事务的经典错误是把多条 INSERT 分成多次 Autocommit 执行结果执行到第三条失败前两条已经落库没有后悔药。实际项目中批量导入数据的正确姿势是包在一个事务里要么全成功要么全失败。5.2 并发控制与锁两个终端抢同一行数据的现象并发控制实验建议开两个 gsql 窗口模拟。用SET TRANSACTION ISOLATION LEVEL设置隔离级别默认是 READ COMMITTED。-- 会话 1 BEGIN; UPDATE book_eg.SC SET Grade 95 WHERE Sno 20210001 AND Cno C001; -- 会话 2此时会阻塞等待 BEGIN; UPDATE book_eg.SC SET Grade 88 WHERE Sno 20210001 AND Cno C001;逻辑说明会话 1 更新了某一行但没提交这行上有了排他锁会话 2 更新同一行时会被阻塞直到会话 1 提交或回滚。如果两个会话互相持有对方需要的锁会形成死锁openGauss 的锁管理器会检测到并自动终止其中一个事务报deadlock detected。这个实验我建议截图保留两个终端的等待状态报告里写清楚死锁检测机制优先回滚代价小的事务另一事务继续执行。这是并发控制报告里最有含金量的一张图。5.3 备份与恢复逻辑备份和物理备份的分工实验八是数据安全的关键。openGauss 备份分逻辑备份和物理备份两类逻辑备份用 gs_dump 导出 SQL 文本物理备份用 gs_basebackup 拷贝数据目录。# 逻辑备份导出整个数据库为 SQL 文件 gs_dump -f /home/omm/db_school_backup.sql -p 26000 db_school # 恢复数据库 gs_restore -d db_school_new /home/omm/db_school_backup.sql # 物理备份全量备份数据目录 gs_basebackup -D /home/omm/base_backup -p 26000参数说明gs_dump -f指定导出文件-p是端口最后的 db_school 是要备份的库名。gs_restore的-d指定目标数据库目标库必须预先存在。gs_basebackup的-D指定备份目录物理备份适合恢复整个实例逻辑备份适合迁移单库单表。生产环境我一般两个都做逻辑备份每日一次物理备份每周一次前者保证快速恢复单表后者保证整机容灾。实验报告建议两种方式各截图一张并注明备份文件大小差异。5.4 这篇报告最容易踩的五个坑现象、原因、解决以下五条来自我实际跑这份实验的踩坑记录每条都是先看到什么报错、再分析为什么、最后怎么解决。坑 1gsql 报“无法连接连接被拒绝”现象执行gsql -d postgres -p 26000后一直卡住或直接拒绝连接。原因两个可能性一是数据库服务没启动二是防火墙拦了 26000 端口。很多人在物理机上装完就忘了启动服务直接执行连接命令。解决先跑gs_om -t status看集群状态如果显示不是 Normal执行gs_om -t start启动如果服务已启动但仍连不上检查防火墙systemctl status firewalld测试环境直接systemctl stop firewalld省事。坑 2建表报“relation already exists”现象第二次跑实验脚本时执行CREATE TABLE报表已存在。原因openGauss 的表在同一 Schema 下不允许重名上一次实验的表没有被删掉。解决建表前加判断或者先执行DROP TABLE IF EXISTS book_eg.Students CASCADE;。实验脚本写成可重复执行的形式这一行放在建表语句前面比报错后再去删表高效得多。坑 3外键创建失败报“no unique constraint matching”现象ALTER TABLE 添加外键时报错提示被引用列没有唯一约束。原因外键引用的目标列必须是主键或唯一索引列。比如 Departments.Dno 建表时如果漏写了 PRIMARY KEY后面拿它做外键引用目标就报这个错。解决\d Departments查看表结构确认 Dno 上有主键约束。没有就ALTER TABLE book_eg.Departments ADD PRIMARY KEY (Dno);补上再建外键。这个顺序问题在交叉引用的多表场景里非常典型。坑 4事务更新后另一个终端查不到数据现象会话 1 UPDATE 并 COMMIT 了会话 2 用 SELECT 仍然看到旧数据。原因会话 2 可能在 REPEATABLE READ 隔离级别下开启了一个快照快照在事务开始时固定之后即使其他事务提交也看不到新数据。另一个可能是会话 2 自己也在一个未提交的事务里。解决在会话 2 执行COMMIT;结束当前事务再重新 SELECT就能看到已提交数据。这个现象本身就是理解 MVCC 快照隔离的最好例子建议保留下来写进报告。坑 5gs_dump 备份权限不足现象用普通用户执行 gs_dump 报权限错误。原因gs_dump 需要对目标库有读权限而且备份文件要写到有写权限的目录。刚建的新用户默认只有登录权限没有数据库对象的读取权限。解决切换到 omm 用户执行备份或者给备份用户GRANT CONNECT ON DATABASE db_school TO db_user1;加上GRANT SELECT ON ALL TABLES IN SCHEMA book_eg TO db_user1;。备份命令尽量走 omm省权限问题。6. 用 JDBC 连接 openGauss 收尾把报告知识落成一个可跑通的 Java 程序实验九是整份报告的压轴用 JDBC 打通 Java 程序和 openGauss。这个实验的完成度决定了整份报告是“数据库操作”还是“数据库应用开发”。JDBC 连接 openGauss 本质上是走 PostgreSQL 协议驱动类名和 URL 格式与 PostgreSQL 几乎一致。import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class DbConnection { public static void main(String[] args) { // 连接参数openGauss 默认端口 26000驱动类为 PG 协议实现 String url jdbc:postgresql://127.0.0.1:26000/db_school; String user db_user1; String password User1234; // 1. 加载驱动 try { Class.forName(org.postgresql.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); return; } // 2. 建立连接 try (Connection conn DriverManager.getConnection(url, user, password); Statement stmt conn.createStatement()) { System.out.println( 连接 openGauss 成功 ); // 3. 查询前面实验创建的学生表 String sql SELECT Sno, Sname, Speciality FROM book_eg.Students; try (ResultSet rs stmt.executeQuery(sql)) { while (rs.next()) { System.out.println(rs.getString(Sno) | rs.getString(Sname) | rs.getString(Speciality)); } } } catch (Exception e) { e.printStackTrace(); } } }逻辑说明代码分三步走——Class.forName加载驱动类到 JVMDriverManager.getConnection建立 TCP 连接并完成认证Statement.executeQuery把 SQL 发给服务端执行。注意try-with-resources写法Java 7 之后连接、语句、结果集都实现 AutoCloseable放在 try 括号里能自动关闭避免连接泄漏。openGauss 的 JDBC 驱动文件是 opengaussjdbc.jar也可以直接用 PostgreSQL 的 postgresql.jar连接协议兼容。参数说明URL 中127.0.0.1是数据库所在主机如果 Java 程序跑在虚拟机外部这里要改成虚拟机 IP26000是 openGauss 端口不是 PostgreSQL 的 5432db_school是第 3 章建的库名。用户名和密码用第 4 章实验创建的用户权限不足时连查询都会报权限错误这也反向验证了前面安全性实验的意义。验证这个程序是否跑通我习惯再加一条检查故意把密码写错观察是否抛PSQLException: FATAL: password authentication failed再把库名写错观察是否抛database xxx does not exist。这两种报错分别验证了连接参数中的认证信息和库名解析比直接打印“连接成功”更能证明程序真的和数据库发生了交互。从最初安装 openGauss 到这一个 Java 类跑出学生表数据九个实验形成了一个完整闭环。我后来每次给新人讲数据库实验都强制他们走一遍这条链路先环境再建表先权限再并发最后 JDBC 收尾。备份好的 SQL 脚本一定要单独存一份虚拟机快照回滚之后重建整个实验环境只需要跑一遍脚本不用从头再敲一遍建表语句。希望这份拆解能帮你在同样的实验路上少走几个来回。本文还有配套的精品资源点击获取