news 2026/10/27 11:49:36

openGauss数据库实验全流程:从建库建表到事务备份与JDBC对账

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
openGauss数据库实验全流程:从建库建表到事务备份与JDBC对账

简介:《数据库系统原理实验》报告面向计算机科学与技术、软件工程专业学生及数据库初学者,围绕 openGauss 环境下的课程实验整理而成,可用于巩固数据库理论、完成实验报告与复习 SQL 操作。压缩包共 1 个 docx 文件,约 3.23MB,内容按实验一至实验九组织,涵盖认识 DBMS、创建数据库表和索引、交互式 SQL、视图、完整性控制、安全性控制、事务与并发控制、备份恢复及 JDBC 连接数据库等主题。文档保留实验目的、内容、步骤、截图要求与结果分析,便于读者对照复现操作、理解权限与事务机制、排查常见问题,也可作为课程作业和考前梳理的参考。目前已有 1525 人学习,适合需要系统练习数据库实验的读者按章节查阅。

1. 这份数据库实验报告书,真正能复用的是九次实验压出来的命令顺序

数据库这门课有个很常见的错位:理论卷面能拿高分,坐到终端前却连一条带外连接的三表查询都要翻笔记。这份《数据库系统原理实验》报告书针对的正是这个落差——它把九个实验串成一条完整链路:装 openGauss、gsql 连上去、建表空间和库、建六张表、建索引、写交互式 SQL、建视图、做完整性与安全性控制、跑事务并发、备份恢复,最后从 Java 侧用 JDBC 连回来。它适合两类人:正在赶实验报告、需要一个能逐条对照的命令清单的计算机类专业学生;以及离开课堂太久、想用开源库把 SQL 手感重新捡回来的开发者。排版模板好抄,值钱的是每一步的命令顺序和那些会报错的边界。

2. 环境落地:从 openGauss 安装到 gsql 连上,有三个必过的关口

环境这一步最容易出现的问题,是装完了却连不上、连上了却找不到库、找到了库却发现自己没权限建表。三个关口分别是:机器资源够不够、管理命令有没有在正确的操作系统用户下执行、端口和库名有没有对上。绕过任何一环,后面八个实验都得停下来补课。

2.1 三种安装路径怎么选:先看你手里有什么机器

报告里列了三种模式,实际操作时选哪条,取决于你手上现成的资源,而不是哪条看起来最“正规”。

安装路径适用条件大致耗时最容易出问题的点
云主机镜像部署有可用的云主机、能拿到管理员权限30 分钟到 1 小时安全组没放行数据库端口、镜像自带的初始口令没记录
虚拟机一键安装本地有 VMware 或 VirtualBox,内存给到 8G 以上1 到 2 小时内存不足导致安装脚本中途退出,回滚不干净
先装 openEuler 再装 openGauss想顺带练 Linux、磁盘留足 40G 以上3 小时以上依赖包缺失、Python 版本不匹配

我一般会建议第一次上手走第二条。一键安装脚本把用户创建、目录初始化、环境变量都替你做了,出错时只要把虚拟机快照回滚重来,代价可控。云主机那条路看着最快,但安全组、内网地址、初始密码三件事只要漏一件,你就会在“连接被拒绝”上耗掉一晚上,而这类问题对新手来说很难自己定位。

还有一条血泪经验:安装前把虚拟机内存固定在 8G,别用动态分配。安装脚本跑到一半因为宿主机内存回收被杀掉,留下的半成品实例比全新环境更难清理——它占着目录和端口,重装时会报“目录非空”。

2.2 omm 用户、gs_om 与 gsql:连接串里每个参数都要能解释

openGauss 装完之后,管理动作必须在安装时指定的操作系统用户下做,报告里叫它 omm。远程登录服务器时你是 root,直接敲数据库命令会得到各种“权限不足”“找不到命令”,这不是数据库的问题,是身份不对。

# 切到数据库安装用户,后续所有管理命令都在这个身份下执行 su - omm # 先看实例状态,再决定要不要启动;-t 后面跟 status/start/stop gs_om -t status gs_om -t start # 连接默认库:-d 指定库名,-p 指定端口,-r 打开行编辑(上下键能翻历史命令) gsql -d postgres -p 26000 -r

这段里每个参数都值得单独说一句。-d postgres里的 postgres 是安装时自动生成的默认库,你要新建的 db_school 不在里面,得先连上这个库才有资格执行CREATE DATABASE。-p 26000是安装时指定的主节点端口,换一台机器、换一次安装都可能不一样,忘了就用gs_om -t status --detail查,别硬猜。-r是打开行编辑,没有它,敲错一个字符就得整行重打,交互式 SQL 实验里能把你逼疯。

gs_om和gs_ctl的区别也常被问。gs_om面向集群,负责实例的整体启动、停止、状态查询;gs_ctl面向单个实例,做 reload、promote 这类更细的操作。日常实验用gs_om足够,改完配置文件想让它生效又不重启,才需要gs_ctl reload。

2.3 元命令和系统表:同一件事的两条查询路径

gsql 里有两套查法:元命令(反斜杠开头)和查系统表。元命令快,适合边做边看;系统表全,适合把结果写进报告或者拿去做脚本判断。我习惯先用元命令定位问题,再用系统表拿准确值。

想看什么元命令等价的系统表查询
有哪些库\lSELECT datname FROM pg_database;
当前库有哪些表\dtSELECT tablename FROM pg_tables;
表结构\d tablename查 pg_attribute、pg_type
表的完整属性\d+ tablename同上,附带存储与压缩信息
有哪些 schema\dnSELECT nspname FROM pg_namespace;
有哪些索引\diSELECT indexname FROM pg_indexes;
有哪些表空间\dbSELECT spcname FROM pg_tablespace;
有哪些用户\duSELECT * FROM pg_user;
有哪些角色\dgSELECT * FROM pg_roles;

pg_user和pg_roles这两张表的关系,正好对应实验里那个辨析点:用户是具体账户,角色是权限集合。pg_user里能看到登录账户,pg_roles里能看到包括rolcanlogin标志在内的全部角色,把某个角色授予某用户之后,用户就继承了这批权限,不必逐条 GRANT。这条设计在后面安全性控制实验里会反复用到。

3. 建库建表建索引:六张表的创建顺序决定你能不能少改三次表

实验二看着最枯燥,实际上是整门课的地基。库、schema、表、索引这四层东西有严格的从属关系,顺序错了,后面所有实验都在一个歪掉的结构上跑。最常见的问题,是表建完了才发现外键互相引用,只能删表重来——而这个代价本来完全可以用一个ALTER TABLE避免。

3.1 表空间、数据库、schema:三级容器不能跳着装

报告里用文件夹做类比:表空间相当于磁盘上的一块预留区域,数据库是这块区域里划分出的逻辑单元,schema 是库内部的名字空间。这个类比基本准确,只是要补一句:数据库在逻辑上独立,跨库查询在 openGauss 里做不了,所以建库时要想清楚。

-- 1. 表空间:LOCATION 指向的必须是已经存在且为空的目录 CREATE TABLESPACE tpcds_local RELATIVE LOCATION 'tablespace/tablespace_1'; -- 2. 建库时直接指定默认表空间,避免以后 ALTER 迁移 CREATE DATABASE db_sc WITH TABLESPACE = tpcds_local; -- 3. 库改名:不能在被改名的库上执行,先切回 postgres ALTER DATABASE db_sc RENAME TO db_school; -- 4. 切库 \c db_school

RELATIVE LOCATION是相对数据目录的路径,写成绝对路径会直接报错;目录非空同样会失败,所以建目录之后别再往里放东西。第三步改名有个隐藏前提:当前会话不能连在 db_sc 上,否则 openGauss 会提示有活动连接。这不是 bug,是防止你在改名的同时还有会话往里写数据。

schema 这条线,报告里给的例子是CREATE SCHEMA book_eg;然后CREATE TABLE book_eg.Teachers(...)。这一步的意义在于隔离:不同 schema 下可以有同名表,多用户环境下每个人建自己的 schema,表名就不会打架。删的时候用DROP SCHEMA book_eg CASCADE;,CASCADE 会把 schema 里的表、视图一起删掉,敲之前先\dn看一眼里面有什么。

3.2 六张表的创建顺序:循环外键必须拆成两步

Teachers、Departments、Students、Courses、SC、Teaches 这六张表里,藏着一个循环引用:Teachers 的 Dno 指向 Departments,Departments 的 Dheadno 又指回 Teachers。谁先建都得引用一个还不存在的表。

处理办法是拆成两步:先建 Teachers 但不带指向 Departments 的外键,再建 Departments 并带上指向 Teachers 的外键,最后ALTER TABLE回补 Teachers 那一边。这是整个实验二里唯一必须打乱顺序的地方,记住这一点,后面五张表就是按依赖关系顺排。

-- 第一步:Teachers 先建,Dno 只留列,不加外键 CREATE TABLE Teachers ( Tno CHAR(20) PRIMARY KEY, Tname CHAR(20) NOT NULL, Sex CHAR(20) CHECK (Sex IN ('男','女')), Birthday DATE, Title CHAR(20), Dno CHAR(20) ); -- 第二步:Departments 引用 Teachers,外键写成表级约束并起名 CREATE TABLE Departments ( Dno CHAR(20) PRIMARY KEY, Dname CHAR(20), Dheadno CHAR(20), CONSTRAINT fk_dept_head FOREIGN KEY (Dheadno) REFERENCES Teachers(Tno) ); -- 第三步:回补 Teachers 的外键 ALTER TABLE Teachers ADD CONSTRAINT fk_teacher_dept FOREIGN KEY (Dno) REFERENCES Departments(Dno);

给约束起名(fk_dept_head)不是为了好看。后面插入违规数据时,报错信息里会带上约束名,你一眼就知道是哪条规则挡住的;不起名的话,报错只给一个系统生成的编号,六张表的外键混在一起排查起来很痛苦。

剩下三张表按依赖顺序排列:Students 依赖 Departments,Courses 独立,SC 依赖 Students 和 Courses,Teaches 依赖 Teachers 和 Courses。

CREATE TABLE Students ( Sno CHAR(20) PRIMARY KEY, Sname CHAR(20) NOT NULL, Sex CHAR(20) CHECK (Sex IN ('男','女')), Birthday DATE, Enrollyear CHAR(20), Speciality CHAR(20), Dno CHAR(20), FOREIGN KEY (Dno) REFERENCES Departments(Dno) ); CREATE TABLE Courses ( Cno CHAR(20) PRIMARY KEY, Cname CHAR(20) NOT NULL, Period SMALLINT, Credit SMALLINT ); CREATE TABLE SC ( Sno CHAR(20), Cno CHAR(20), Grade NUMERIC(5,1), PRIMARY KEY (Sno, Cno), FOREIGN KEY (Sno) REFERENCES Students(Sno), FOREIGN KEY (Cno) REFERENCES Courses(Cno) );

Courses 里的 Period 和 Credit 用 SMALLINT 是合理的,报告里那段关于取值范围的辨析说的就是这个:学时和学分不可能超过 32767,用 INT 是浪费空间。真正要注意的是 SC 的主键——PRIMARY KEY (Sno, Cno)是复合主键,它同时保证了“一个学生一门课只能有一条选课记录”,这条约束在插入重复数据时会直接拦住你。

建完之后用\dt确认六张表都在,再逐个\d+ tablename把表结构截图进报告。这一步别省,报告要求截图下方带编号和图题,早截比事后补好。

3.3 列级约束与表级约束怎么分

报告里花了不少篇幅讲这两者的区别,落到实操只有三条判断标准。

位置不同:列级约束写在列定义后面,用空格分隔;表级约束写在所有列定义之后,用逗号分隔。能力不同:涉及多个列的约束,比如复合主键、复合外键,只能写成表级;非空和默认值这类只作用于单列的,写成表级反而不被支持。可读性不同:表级约束可以起名,列级不行。

一个具体的取舍:Students 表里的CHECK (Sex IN ('男','女'))写成列级完全够用,因为它只约束一列。但如果你还想加一条“入学年份不能晚于出生年份加 30 年”这种跨列规则,就必须升级成表级约束。我在带实验时见过有人在列级里硬塞跨列 CHECK,语法上过不去,浪费半小时。

3.4 索引建在哪一列,用 \di 和执行计划验证

索引这一节最容易走过场:照着CREATE INDEX Student_Dept ON Students(Dno);敲一遍,看到\di里有输出就算完成。但实验报告要求写“结果分析”,你得说清楚这条索引为什么建在 Dno 上。

原因在查询模式:学生按院系筛选是最常见的过滤条件,WHERE Dno = 'D01'这种等值查询如果没索引,就得全表扫描。Dno 是外键列,选择性谈不上高(一个院系下可能有几百个学生),但比起全表扫仍然是数量级的差距。

-- 在学生表的外键列上建索引 CREATE INDEX Student_Dept ON Students(Dno); -- 确认索引已创建,注意主键会自动生成一个同名索引,这里应该看到两条 \di -- 用执行计划验证:有索引时应出现 Index Scan 而不是 Seq Scan EXPLAIN SELECT * FROM Students WHERE Dno = 'D01';

\di列出来的索引会比手工建的多,这是正常的——DBMS 会为主键自动建索引,那条不是你写的,但同样占空间、同样影响写入性能。这一点在报告的分析部分值得写一句:索引不是越多越好,每多一条索引,INSERT 和 UPDATE 就多一份维护开销。

EXPLAIN的输出要会看关键字段:扫描方式(Seq Scan / Index Scan)、预估行数、执行代价。数据量只有几十行时,优化器很可能仍然选全表扫描,因为走索引的代价反而更高。这时候别怀疑索引没生效,插几百行测试数据再看一次就正常了。

4. 交互式 SQL 与视图:查询跑不出来时按四步往下拆

实验三到实验七是四个实验,但它们共享同一套调试方法:先确认表里有没有数据,再确认连接条件写没写对,然后确认过滤条件放在 WHERE 还是 HAVING,最后才看 SELECT 列有没有算错。顺序颠倒过来,你会在一个空结果集上反复改列名。

4.1 多表连接:先把结果集缩小再 JOIN

三表连接的写法有几种,结果一样,可读性差很多。报告里的例子是学生、课程、成绩三张表,我一般建议按“主表 → 关联表 → 关联表”的顺序写,把过滤条件尽量往前放。

-- 查成绩 80 分以上的学生姓名、课程名和分数 SELECT s.Sname, c.Cname, sc.Grade FROM Students s JOIN SC sc ON s.Sno = sc.Sno JOIN Courses c ON sc.Cno = c.Cno WHERE sc.Grade >= 80 ORDER BY sc.Grade DESC;

逻辑上,SQL 的执行顺序和书写顺序不一致:先 FROM 确定数据源,再 ON 做连接匹配,然后 WHERE 过滤,接着 GROUP BY 分组、HAVING 过滤组,之后才是 SELECT 取列和 ORDER BY 排序。理解这个顺序,你就能解释为什么 WHERE 里不能写聚合函数——那时候还没分组。

参数上要注意的是别名。Students s这种短别名在单表查询里可有可无,三表以上就是刚需,否则每列都得写全表名,一行 SQL 能拉到屏幕外。

结果不对时的排查路径:先把 JOIN 换成单表SELECT count(*)确认每张表都有数据;再把 WHERE 去掉看连接本身是否正确(行数应该是各表匹配数的乘积量级);最后把 SELECT 的列逐个加上,看哪一列开始出问题。

4.2 聚合与分组:WHERE 和 HAVING 的分界线

分组查询的典型错误是把聚合条件写进 WHERE。

-- 统计每个学生的平均分,没有选课的学生不参与统计 SELECT s.Sno, s.Sname, AVG(sc.Grade) AS avg_grade FROM Students s JOIN SC sc ON s.Sno = sc.Sno GROUP BY s.Sno, s.Sname HAVING AVG(sc.Grade) >= 60 ORDER BY avg_grade DESC;

HAVING AVG(sc.Grade) >= 60里的聚合函数只能出现在 HAVING,不能出现在 WHERE。原因是 WHERE 在分组之前执行,那时候 AVG 还没算出来。这条规则几乎所有教材都写,但真正写错的人不少,因为顺序颠倒时数据库报的错很含糊,只说“聚合函数不能出现在此处”。

GROUP BY 后面列了 Sno 和 Sname 两列,这是必须的:SELECT 里出现的非聚合列,都要出现在 GROUP BY 里(除非该列函数依赖于分组键)。Sno 是主键,理论上只写 Sno 就够,但很多实现不认函数依赖,写全更保险。

想把“没选课的学生”也算进去,就得把内连接换成左外连接,同时把过滤条件从 WHERE 挪到 ON 里,否则左连接会被 WHERE 退化成内连接——这是外连接最经典的翻车点,也是实验三和实验四之间最值得对照的一次改写。

4.3 视图:把复杂查询固化,也把依赖固化

视图在报告里是实验四的独立内容,实际用起来,它就是给一段查询起了个名字。

-- 把学生和院系的连接固化成视图 CREATE VIEW v_student_dept AS SELECT s.Sno, s.Sname, d.Dname FROM Students s JOIN Departments d ON s.Dno = d.Dno; -- 查视图的定义和列属性 \d+ v_student_dept -- 像查表一样查视图 SELECT * FROM v_student_dept WHERE Dname = '计算机系';

视图带来两件事。好事是复杂查询不用每次重写,权限也好控制——你可以只把视图的 SELECT 权限给某个用户,让他看不到基表的其他列。麻烦事是依赖被固化了:基表改名、删列、改类型,视图会一起失效,而且报错时机是查询视图的那一刻,不是改基表的那一刻。

我一般会提醒一句:视图上做更新要格外小心。简单视图(单表、无聚合、无 DISTINCT)通常可更新,多表连接的视图基本不可更新,硬写 UPDATE 会报错。实验报告里如果要写这部分,把“不可更新的原因”讲清楚比贴一条报错更有价值。

4.4 完整性与安全性:约束和权限分别在哪一层生效

实验五和实验六解决的是两个不同层面的问题。完整性管的是“数据本身对不对”,安全性管的是“谁能碰这些数据”。两者都靠 DDL 语句配置,但生效时机完全不同。

完整性这一层,四类约束各有分工:NOT NULL 挡住空值,CHECK 挡住不合法的值域,PRIMARY KEY 挡住重复和空值,FOREIGN KEY 挡住引用不存在的记录。加约束用 ALTER TABLE,注意已有数据不满足新约束时会直接失败。

-- 给入学年份加一条值域约束,注意已有数据必须先合规 ALTER TABLE Students ADD CONSTRAINT ck_enrollyear CHECK (Enrollyear BETWEEN '2000' AND '2030'); -- 故意插一条违规数据,验证约束确实生效(应该报错) INSERT INTO Students (Sno, Sname, Sex, Enrollyear) VALUES ('S999', '测试', '男', '1990');

第二条 INSERT 报错是预期行为,把报错信息截图放进报告,这就是“约束生效”的证据。如果它没报错,说明约束没建上,回去用\d Students看看约束列表里有没有 ck_enrollyear。

安全性这一层,颗粒度是对象加操作。逐条 GRANT 能让权限最小化,但用户一多就难维护,所以更好的做法是先建角色,再把角色授予用户。

-- 建一个只读角色,把查询权限挂到角色上 CREATE ROLE role_reader; GRANT SELECT ON Students, Courses TO role_reader; -- 建用户并把角色授予他 CREATE USER u_query IDENTIFIED 'YourPass@2024'; GRANT role_reader TO u_query; -- 收回课程表的查询权限,验证 REVOKE 的传递效果 REVOKE SELECT ON Courses FROM role_reader;

第三步的 REVOKE 有个容易忽略的点:从角色上收回权限,所有被授予该角色的用户会同时失去这个权限。这正是角色存在的意义——权限变更只在一个地方发生。密码要满足复杂度要求,太简单的口令在建用户那一步就会被拒绝,报错信息里会写清楚规则,照着改就行。

4.5 事务与并发:两个 gsql 会话手动复现

实验七讲事务,光看定义没用,得亲手制造一次锁等待。开两个终端,都连同一个库。

-- 会话 A:开启事务并更新,先不提交 BEGIN; UPDATE Courses SET Credit = Credit + 1 WHERE Cno = 'C01'; -- 停在这里,不要 COMMIT
-- 会话 B:先读,再试着改同一行 SELECT * FROM Courses WHERE Cno = 'C01'; -- 能读,读到的是旧值 UPDATE Courses SET Credit = 0 WHERE Cno = 'C01'; -- 这里会卡住

会话 B 的 UPDATE 会一直挂着,直到 A 执行 COMMIT 或 ROLLBACK。这个现象就是行级锁:A 没提交前,那一行的写锁在它手上。B 的 SELECT 能读到旧值,说明默认的 READ COMMITTED 隔离级别下,读不阻塞写、写阻塞写。

验证完记得把 A 的事务结束掉,ROLLBACK比COMMIT更安全——回滚能把你刚才的改动撤掉,避免测试数据污染后续实验。

再补一组对比:把隔离级别提到 SERIALIZABLE,重新跑一遍上面的流程,你会发现 B 的 SELECT 都可能被阻塞或者报序列化冲突。这个对比写进报告,比单纯抄定义有说服力得多。

5. 避坑与排查:九个实验里最容易翻车的五处

这一节列的五条,都是我在跟着这份报告走完整流程时真实撞过的,每条按“现象 → 原因 → 解决”写,遇到了直接对号入座。

5.1 连接层:本机连得上,远程连不上

现象:在数据库服务器上用 gsql 一切正常,换到 Windows 客户端或者另一台虚拟机,报FATAL: Forbid remote connection或者连接直接被拒绝。

原因:openGauss 安装后默认的监听配置和客户端认证文件只放行了本机连接,远程访问需要在pg_hba.conf里显式加一条 host 规则,同时确认postgresql.conf里监听地址不是只绑了回环。

解决:找到实例的数据目录,编辑pg_hba.conf,加一行类似host all all 192.168.0.0/24 sha256,然后用gs_ctl reload让配置生效,不用重启实例。改完先用gsql -h 服务器IP -p 26000 -d postgres -U 用户名测一次,通了再做后续实验。

5.2 对象可见性:表明明建了,\dt里却没有

现象:建表语句没报错,切到另一个会话\dt看不到,或者SELECT时报“表不存在”。

原因:两个可能。一是建表时带了 schema 前缀,表的全名是book_eg.teachers,不在当前 search_path 里;二是大小写——不加双引号的标识符会被折叠成小写,CREATE TABLE Teachers实际存的是 teachers,你写SELECT * FROM Teachers能匹配上,但写"Teachers"就匹配不上了。

解决:先\dn看有哪些 schema,再\d+ schema名.表名确认对象是否存在,最后用SHOW search_path;看当前会话的搜索路径。要长期省事,就在建表前SET search_path TO book_eg, public;,让后续语句默认落在这个 schema 下。

5.3 外键插入顺序:单条插入都对,批量灌数据就报错

现象:手工一条条 INSERT 没任何问题,用脚本批量灌数据时中途报violates foreign key constraint。

原因:外键要求被引用的记录先存在。批量插入时如果按表的字母顺序或者文件里的书写顺序灌,子表可能先于父表写入,第一条就撞上外键。

解决:按依赖拓扑序灌数据——先 Teachers,再 Departments,然后回补 Teachers 的 Dno,接着 Students、Courses,最后 SC 和 Teaches。删除时反过来,先删子表再删父表,或者用ON DELETE CASCADE让数据库自己处理。灌数据前先TRUNCATE所有表并按逆序清空,能避免上一轮残留数据干扰。

5.4 字符类型:CHAR 定长补空格,比较和拼接都出意外

现象:Sex列定义成CHAR(20),存进去的是“男”,SELECT LENGTH(Sex)返回 20,字符串拼接出来后面拖一串空格,和另一个表关联时偶尔匹配不上。

原因:CHAR 是定长类型,长度不足会用空格补齐到声明长度。比较时多数实现会自动去掉尾部空格,但LENGTH、字符串拼接、LIKE这些操作不会。

解决:性别、姓名、专业这类长度不固定的字段,直接用VARCHAR(20),别用 CHAR。已经建好的表用ALTER TABLE ... ALTER COLUMN ... TYPE VARCHAR(20)改,改之前确认表里没数据或者数据都合规。这条经验在真实项目里同样成立——CHAR 只在长度严格固定的场景(比如定长编码)才值得用。

5.5 并发测试:UPDATE 卡住不返回,以为数据库挂了

现象:按 4.5 节的步骤做并发实验,会话 B 的 UPDATE 一直停在那里,等了几分钟也没动静,Ctrl+C 都退不出来。

原因:这不是死机,是行锁等待。会话 A 的事务没提交,那一行的写锁还握在它手上,B 只能排队。如果 A 的终端被你关掉了但事务没结束,这个锁会一直挂着。

解决:另开一个会话查SELECT pid, state, query FROM pg_stat_activity WHERE state != 'idle';,找到阻塞的会话,确认之后再决定是让它 COMMIT 还是直接 terminate。做这类实验养成习惯:每个 BEGIN 后面都想好什么时候结束它,测试完立刻 ROLLBACK,别把未提交事务留在那里过夜。

6. 备份恢复与 JDBC 对账:把“能跑通”变成“能验证”

实验八和实验九最容易做成形式主义:备份命令跑完看到文件生成了就交差,JDBC 打印一句“连接成功”就截图。这两步真正要验证的东西,是数据在离开原库之后还能不能被还原、还能不能被另一个程序读到。我一般用“三方对账”来收尾:原库行数、恢复库行数、JDBC 查出来的行数,三个数必须一致。

# 逻辑备份:整库导出成一个可读的 SQL 文本 gs_dump -U omm -W '口令' -p 26000 -f /home/omm/backup/db_school.sql db_school # 恢复到新库:先建空库,再灌脚本 gsql -d postgres -p 26000 -c "CREATE DATABASE db_school_bak;" gsql -d db_school_bak -p 26000 -f /home/omm/backup/db_school.sql # 对账第一步:两张表的行数必须相同 gsql -d db_school -p 26000 -c "SELECT count(*) FROM Students;" gsql -d db_school_bak -p 26000 -c "SELECT count(*) FROM Students;"

gs_dump导的是逻辑结构加数据,文本可读、可跨版本迁移,缺点是库大了之后慢。物理备份gs_basebackup快得多,但只能恢复到同版本同架构的实例上,做实验用逻辑备份就够。

备份方式产出物恢复粒度适用场景
gs_dump文本 SQL 或自定义格式库、schema、表迁移、单表找回、留档
gs_basebackup数据目录的物理副本整个实例灾难恢复、主备搭建

JDBC 那一步,对账的意义比“连接成功”大得多。连上之后执行一条SELECT count(*) FROM Students,把结果和上面两个数比对,三个数对齐才算这条链路真的通了。

// openGauss 走 PostgreSQL 协议,用配套驱动,别随手抓一个旧版 pg 驱动 Class.forName("org.opengauss.Driver"); String url = "jdbc:postgresql://192.168.0.10:26000/db_school"; try (Connection conn = DriverManager.getConnection(url, "u_query", "YourPass@2024"); Statement st = conn.createStatement(); ResultSet rs = st.executeQuery("SELECT count(*) FROM Students")) { rs.next(); System.out.println("JDBC 侧行数: " + rs.getInt(1)); // 必须和原库一致 }

这里的坑集中在驱动和认证方式上:openGauss 默认的密码加密算法和老版本 PostgreSQL 驱动不匹配,用错驱动会在认证阶段报“Invalid username/password”,看起来像密码错了,其实换驱动就好。另外 URL 里的端口是 26000,不是 PostgreSQL 惯用的 5432,抄示例代码时最容易漏改这一处。

这份报告书我前后翻过三遍,每次都是从“建库”那一节开始逐条敲。后来形成一个习惯:不管多小的实验,只要涉及数据搬迁或者跨程序访问,收尾必须走一遍三方对账——原库、恢复库、客户端,三个数对不上就说明中间某一步被跳过了,绝不靠“看起来成功了”过关。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 11:49:08

DataEase日志查看与问题排查全指南

1. DataEase日志查看命令全解析 作为DataEase平台的深度用户,我经常需要查看系统日志来排查问题。经过半年多的实战积累,这套日志查看命令组合拳已经成为我的日常工具箱必备技能。今天就把这些干货毫无保留地分享给大家,包含从基础查询到高级…

作者头像 李华
网站建设 2026/10/27 11:47:43

基于K-Means与PCA的评论情感分析及ECharts可视化实现

这个题目我第一次看到的时候,第一反应是"名字太长了吧"。但是如果你把这串字拆开,其实特别清晰:前面半句是算法内核——K-Means聚类加主成分分析(PCA)做消费者评论情感挖掘,后面半句是系统呈现—…

作者头像 李华
网站建设 2026/10/27 11:45:10

JDBC 连 DB2 三大高频翻车点:权限、名称解析与事务提交

简介:这份资源是吉林大学《数据库应用程序开发》课程的实验报告,面向正在学习Java与DB2数据库交互的高校学生及自学者,帮助其理解JDBC编程的核心流程与常见问题排查。报告围绕JDBC连接、Statement与PreparedStatement使用、结果集遍历、事务提…

作者头像 李华
网站建设 2026/10/27 11:43:35

云真机调试与AI Agent接入:ADB通道原理及CLI自动化实践

1. 云真机调试这件事,为什么值得重新聊一遍做过 Android 开发的人对真机调试的痛都不陌生。本地插一台手机,USB 线一插,adb devices一敲,看起来很简单。但真正在团队协作、持续集成、远程办公这些场景里跑起来,问题就全…

作者头像 李华
网站建设 2026/10/27 11:42:48

计算图编排与GE引擎在分布式计算中的优化实践

1. 计算图编排与GE引擎的核心价值 在分布式计算和机器学习领域,计算图(Computational Graph)已经成为现代算法实现的基础抽象。Graph Engine(GE)作为专门针对计算图进行优化的执行框架,其核心价值在于将复杂…

作者头像 李华
网站建设 2026/10/27 11:42:30

PyTorch DDP 与 JAX pmap 分布式训练差异及迁移实践

1. 从一次多卡训练翻车说起上周帮一个朋友调一个多卡训练的任务,他之前一直用 PyTorch,这次因为项目需要换成了 JAX。代码写完之后跑单卡没问题,一上 8 卡就各种奇怪的报错——有的是 shape 对不上,有的是梯度莫名其妙变成 NaN&am…

作者头像 李华