简介广东工业大学数据库课程配套实验与课程设计资料基于openGauss平台覆盖从基本表建立、查询、索引视图到存储过程与触发器的完整实验链。内容包含实验报告、Java JDBC实现源码、可执行class文件、运行日志及结果截图并配有课程设计项目适合广工学生及使用openGauss学习数据库的初学者对照练习。压缩包共64个文件以Java源码与class文件为主另有jar驱动、配置文件和图片素材整体约6.93MB结构清晰便于按实验编号检索。目前已有2930人浏览学习可作为实验报告撰写、JDBC编程实践与课堂设计参考。学习者可从中获取完整实验思路、关键SQL语句、触发器与存储过程定义示例以及基于JDBC连接openGauss的实务代码省去从零摸索的时间。1. openGauss实验平台广工数据库实验的主战场拿到广工数据库实验指导书那一刻多数人的第一反应是怎么不是MySQL这门课的实验平台是华为开源的openGauss一个基于PostgreSQL内核的国产数据库。它的SQL方言、存储过程语法、连接管理方式都和MySQL有明显差异很多同学用MySQL的习惯写实验结果在openGauss上报错报得怀疑人生。这篇笔记把整个流程串一遍——从openGauss安装部署流程、建库建表、SQL查询、存储过程、触发器到课程设计的工程化落地顺带把那些让实验卡壳的坑逐个点出来。适合正在做这门实验的本科生也适合准备拿openGauss做数据库课程设计的人。2. openGauss环境准备安装部署流程与三种常用连接方式2.1 服务端安装实验室预装和自己部署是两码事广工实验机房通常已经把openGauss装好了你登录进去直接能用。但课设阶段要自己部署一套或者你想在宿舍笔记本上复现实验就得知道安装流程的完整链路。openGauss服务端不支持root用户直接初始化这是个硬约束很多人第一次装就卡在这里。# 创建openGauss专用的操作系统用户服务端不允许root直启 useradd -m omm echo Gauss2022 | passwd --stdin omm # 解压安装包到统一目录注意x86和ARM架构的包不通用 tar -zxvf openGauss-3.x.x-CentOS-x86_64.tar.gz -C /opt/opengauss # 切换到omm用户加载环境变量脚本 su - omm source /opt/opengauss/install/etc/env.sh # 初始化数据目录-D指定数据目录-U指定初始超级用户名 # --pwfile里放初始化用户的密码密码要求含大小写和数字 gs_initdb -D /data/opengauss -U gaussdb --pwfile/home/omm/pwfile.txt # 启动数据库-D必须指向刚才初始化的目录 gs_ctl start -D /data/opengauss代码逻辑说明安装的核心不是解压而是gs_initdb这一步——它决定数据目录、初始用户和密码策略。-U gaussdb指定超级用户名这个名称会在后续所有连接里反复用到--pwfile指向一个包含密码的文本文件openGauss对初始密码有强度要求纯数字或纯字母会被拒绝。gs_ctl start启动后服务默认监听本机5432端口和PostgreSQL一致。参数说明CentOS-x86_64标识适用于x86架构的CentOS系统ARM版包名里通常带aarch64。如果你的笔记本是M系列芯片或者鲲鹏环境要选对应包否则解压后执行会报无法执行二进制文件。初始化之前建议先把/data/opengauss目录权限改成omm拥有chown -R omm:omm /data/opengauss不然初始化会因权限问题在中途翻车。2.2 状态检查服务没起来后面全是白做启动之后不要急着连客户端先确认服务状态和三件套进程在跑、端口在听、日志无报错。# 查看服务运行状态包括进程PID、启动时间、数据目录 gs_ctl status -D /data/opengauss # 检查端口监听5432是openGauss默认端口 ss -tlnp | grep 5432 # 看日志尾部启动失败的原因基本都在里面 tail -50 /data/opengauss/log/opengauss.log常见做法是三条命令顺序执行对排查很有帮助。如果ss看不到5432端口多半是初始化路径和启动路径不一致或者环境变量没source成功。日志里出现FATAL级别的报错按关键词去搜基本都能找到答案。有一点注意openGauss的日志目录结构和PostgreSQL不完全一样以实际安装位置的log目录为准别死记路径。2.3 客户端连接gsql和Data Studio两条路openGauss官方配套的图形客户端是Data Studio实验指导书里一般推荐用它。但在服务器上或者排错场景下gsql命令行客户端更直接而且存储过程调试时命令行反馈比图形界面清爽。# 本机通过gsql连接postgres库-d是数据库名-U是用户名 gsql -d postgres -U gaussdb -p 5432 -h 127.0.0.1 # 连接成功后查看当前库的所有表 \d # 退出客户端交互界面用\q \q参数说明-d postgres是openGauss初始化后自带的默认数据库-U gaussdb对应2.1里gs_initdb -U指定的用户名-h 127.0.0.1代表本机回环地址。如果要从Windows笔记本连实验室服务器-h要改成服务器的IP同时服务端必须开启了远程连接——这一步默认是关的具体怎么开在第5章的避坑内容里详说。Data Studio那边本质是JDBC连接填主机、端口、数据库名、用户名、密码和gsql的参数一一对应理解了命令行就能理解图形界面填什么。3. 建库建表与SQL查询别把MySQL习惯带进openGauss3.1 建库建表数据类型和约束的第一道坎实验里第一步通常是建库建表。openGauss的SQL整体上遵循SQL标准但细节和MySQL有差异比如自增列的写法、字符类型的行为。照着MySQL的AUTO_INCREMENT来写在openGauss里会直接报语法错误。-- 建库指定UTF8编码和template0模板避免继承本地化设置 CREATE DATABASE library ENCODING UTF8 TEMPLATE template0; -- 切到目标库 \c library -- 学生表学号定长用CHAR姓名字段用VARCHAR CREATE TABLE student ( sno CHAR(8) PRIMARY KEY, sname VARCHAR(20) NOT NULL, sex CHAR(2) DEFAULT 男 CHECK (sex IN (男, 女)), dept VARCHAR(30) DEFAULT 计算机学院, birth DATE ); -- 图书表自增主键用SERIALopenGauss兼容PostgreSQL风格 CREATE TABLE book ( book_id SERIAL PRIMARY KEY, title VARCHAR(100) NOT NULL, stock INT NOT NULL DEFAULT 1 CHECK (stock 0), pub_date DATE ); -- 借阅表联合主键加外键模拟学生和图书的多对多关系 CREATE TABLE borrow ( sno CHAR(8) REFERENCES student(sno), book_id INT REFERENCES book(book_id), borrow_date DATE DEFAULT CURRENT_DATE, PRIMARY KEY (sno, book_id, borrow_date) );逻辑说明ENCODING UTF8配合TEMPLATE template0是为了避免从默认模板库继承字符集和排序规则否则后续插入中文数据可能出现乱码或排序异常。CHAR(8)是定长字段学号长度固定、不会出现长度波动用它比VARCHAR更合适sname这类长度不固定的用VARCHAR(20)。CHECK约束在openGauss里执行很严格插入sex字段不是“男”或“女”的记录会直接拒绝这在实验数据校验里是得分点。参数说明SERIAL是openGauss兼容PostgreSQL的自增列实现等价于INT加默认序列。注意和MySQL的AUTO_INCREMENT不同SERIAL会自动创建一个序列对象你在\d book里能看到它。REFERENCES是外键约束的简写形式实验报告里写外键时最好把ON DELETE CASCADE这类级联策略也考虑进去否则删除父表记录会被外键挡住。3.2 多表查询和聚合实验里最容易扣分的部分查询实验占整个实验报告的大头特别是多表JOIN、分组聚合、HAVING过滤这三件事的组合。很多同学这里丢分不是因为SQL写错而是不理解执行顺序导致在WHERE里写了聚合条件。-- 查询每个系学生数量只显示人数超过2的系 SELECT dept, COUNT(*) AS stu_count FROM student GROUP BY dept HAVING COUNT(*) 2 ORDER BY stu_count DESC; -- 查询借阅次数最多的前五本书 SELECT b.title, COUNT(*) AS borrow_times FROM borrow br JOIN book b ON br.book_id b.book_id GROUP BY b.title ORDER BY borrow_times DESC LIMIT 5; -- 查询所有借阅过图书的学生姓名和书名 SELECT s.sname, b.title FROM student s JOIN borrow br ON s.sno br.sno JOIN book b ON br.book_id b.book_id ORDER BY s.sno;逻辑说明执行顺序是FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT所以“人数超过2的系”这个条件必须放在HAVING里而不能放WHERE因为WHERE在分组之前执行拿不到聚合后的结果。第二个查询用JOIN把借阅表和图书表关联起来注意COUNT(*)统计的是借阅记录条数而GROUP BY b.title按书名分组——如果两本书同名会被合并实验数据里最好保证书名唯一或者改用b.book_id分组。参数说明LIMIT 5是openGauss兼容PostgreSQL的写法MySQL里习惯写LIMIT 0, 5那种带偏移量的形式openGauss也支持但建议直接用LIMIT 5配合ORDER BY语义更清晰。COUNT(*)和COUNT(字段)行为不同COUNT(字段)会跳过NULL值统计借阅次数时两者结果可能不一致这点在实验报告里可以写进分析中是加分项。3.3 索引、视图和事务实验里的进阶得分点索引和视图通常是实验报告的附加题或者课设中的性能优化点。事务则是单独一块实验内容考察你对COMMIT和ROLLBACK的理解。-- 给借阅表的book_id建索引多表JOIN时性能提升明显 CREATE INDEX idx_borrow_book ON borrow(book_id); -- 创建视图WITH CHECK OPTION保证插入数据也满足视图条件 CREATE VIEW v_avail_book AS SELECT book_id, title, stock FROM book WHERE stock 0 WITH CHECK OPTION; -- 事务借书要同时更新库存和插入借阅记录失败就回滚 BEGIN; UPDATE book SET stock stock - 1 WHERE book_id 1; INSERT INTO borrow(sno, book_id, borrow_date) VALUES (20220001, 1, CURRENT_DATE); COMMIT; -- 如果中间任何一句报错执行 ROLLBACK; 让前面的修改全部撤销逻辑说明索引的核心价值是减少扫描行数idx_borrow_book让JOIN条件br.book_id b.book_id不必全表扫描。视图v_avail_book把“可借图书”的查询逻辑固化下来加了WITH CHECK OPTION之后通过视图插入数据时也会强制校验stock 0这个条件这是数据库实验里视图部分很喜欢考的隐藏点。事务部分用BEGIN开启、COMMIT提交ROLLBACK回滚——典型场景就是库存不够时整个借书动作应该全部取消而不是只更新库存不插记录。参数说明CREATE INDEX默认是非唯一索引如果业务上需要唯一性可以加UNIQUE关键字。视图CREATE VIEW在openGauss里支持OR REPLACE修改视图定义时不用先DROP再CREATE这个细节在验证脚本时能省不少事。4. 存储过程与触发器PL/pgSQL写法、参数与异常处理4.1 为什么实验一定要你写存储过程数据库实验和课设里存储过程是必考项。原因是它能把多条SQL封装成一个原子操作在业务层只调用一个函数名不用暴露具体表结构。openGauss的存储过程语言是PL/pgSQL语法基于PostgreSQL和MySQL的存储过程差异很大。最典型的是MySQL用CREATE PROCEDUREopenGauss更常用CREATE FUNCTION而且过程体内变量声明在DECLARE段赋值用SELECT INTO——这些细节不提前熟悉写出来的代码会频繁报语法错误。4.2 存储过程骨架变量、游标与异常处理实验里最常见的存储过程场景是“借书业务”检查库存、扣减库存、插入借阅记录任何一个环节失败都要回滚。下面这个例子完整覆盖了变量声明、条件控制、异常处理三个要点。-- 存储过程本质上是PL/pgSQL函数用CREATE OR REPLACE FUNCTION创建 CREATE OR REPLACE FUNCTION borrow_book(p_sno CHAR(8), p_book_id INT) RETURNS TEXT LANGUAGE plpgsql AS $$ DECLARE v_stock INT; BEGIN -- 把库存先取出来SELECT INTO是PL/pgSQL的取值方式 SELECT stock INTO v_stock FROM book WHERE book_id p_book_id; -- 库存不足直接抛异常注意RAISE EXCEPTION会终止整个事务 IF v_stock 0 THEN RAISE EXCEPTION 图书 % 库存不足, p_book_id; END IF; -- 更新库存 插入借阅记录 UPDATE book SET stock stock - 1 WHERE book_id p_book_id; INSERT INTO borrow(sno, book_id, borrow_date) VALUES (p_sno, p_book_id, CURRENT_DATE); RETURN 借阅成功; -- 异常处理出现任何错误时回滚并抛出错误信息 EXCEPTION WHEN OTHERS THEN RAISE EXCEPTION 借阅失败: %, SQLERRM; END; $$;逻辑说明DECLARE段声明变量v_stock实际执行时用SELECT stock INTO v_stock把当前库存取到变量里这是PL/pgSQL和MySQL存储过程最大的语法差异——MySQL里用SET var ...或者SELECT ... INTO的写法不同openGauss的SELECT INTO更接近Oracle风格。RAISE EXCEPTION不只是打印一条错误它会终止当前事务并进入异常块配合EXCEPTION WHEN OTHERS THEN统一抛给调用方保证借书和库存扣减的原子性。参数说明p_sno和p_book_id的传参方式用了IN参数的默认形式。openGauss还支持OUT参数和INOUT参数如果实验里要求返回多个值可以用OUT参数配合RETURNS RECORD。SQLERRM是异常信息的内置变量把它拼进RAISE EXCEPTION里能保留原始错误上下文排查问题时比单纯返回“借阅失败”有用得多。4.3 触发器自动记录操作日志触发器是实验里的另一个高频考点。场景通常是借阅表每次插入一条记录自动往日志表里写一行。openGauss的触发器函数必须返回TRIGGER类型这和普通存储函数不一样少了这个返回类型定义会直接报错。-- 先建一个日志表用来记录每次借阅操作 CREATE TABLE borrow_log ( log_id SERIAL PRIMARY KEY, sno CHAR(8), book_id INT, op_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 触发器函数必须返回TRIGGER类型这是openGauss的硬性要求 CREATE OR REPLACE FUNCTION fn_borrow_log() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN -- NEW代表即将插入的新行直接从NEW里取字段值 INSERT INTO borrow_log(sno, book_id) VALUES (NEW.sno, NEW.book_id); RETURN NEW; END; $$; -- 给borrow表挂AFTER INSERT触发器插入后自动执行日志函数 CREATE TRIGGER trg_borrow_log AFTER INSERT ON borrow FOR EACH ROW EXECUTE FUNCTION fn_borrow_log();逻辑说明NEW是触发器里的隐藏变量代表INSERT操作中即将写入的新记录行。触发器函数里通过NEW.sno、NEW.book_id直接取新行的字段值写入日志表。AFTER INSERT表示在插入操作成功之后执行如果插入失败触发器不会运行日志表的写入也不会发生——这个时序关系在实验报告里写清楚能体现你对约束正确性的理解。参数说明FOR EACH ROW表示行级触发器每插入一行触发一次如果是FOR EACH STATEMENT一个INSERT语句只触发一次即使插入了100行。实验里要求“自动记录每次操作”一般用FOR EACH ROW。注意openGauss同时兼容EXECUTE FUNCTION和EXECUTE PROCEDURE两种写法但官方推荐FUNCTION新版文档里已经逐步淡化PROCEDURE的说法了。5. openGauss避坑指南五个让实验卡壳的常见问题5.1 现象gsql执行SQL脚本出现中文乱码实验数据里几乎必然有中文比如学生姓名、书名。用Data Studio导入或gsql执行脚本时经常出现插入时正常、查询出来全是??或者乱码符号。原因客户端字符集和服务端字符集不一致。openGauss服务端UTF8编码而gsql客户端的client_encoding可能默认成了SQL_ASCII或操作系统本地编码。解决连接后先执行SET client_encoding TO UTF8;或者在启动gsql之前设置环境变量export PGCLIENTENCODINGUTF8。验证方法很简单插入一条中文记录查出来正常就说明通道通了。脚本文件本身也要保存为UTF8无BOM格式Windows记事本保存的UTF8带BOM执行时第一行可能报语法错用VS Code或Notepad重存一下即可。5.2 现象远程连接被拒绝Data Studio连不上实验室服务器在宿舍用Data Studio连机房的openGauss报Connection refused或超时。自己笔记本上gsql连接本机没问题把-h改成服务器IP就连不上。原因openGauss默认配置下只监听本机回环地址而且pg_hba.conf里的访问规则默认拒绝远端IP。这两个文件分别是postgresql.conf和pg_hba.conf都在数据目录下。解决改postgresql.conf里的listen_addresses为*或具体IP改pg_hba.conf加一行host all all 192.168.1.0/24 sha256然后重启服务或执行gs_ctl reload让配置生效。这条避坑建议也提示你做课设答辩当天最好提前一天把网络策略搞定别赌现场的Wi-Fi和服务器防火墙是通的。5.3 现象存储过程里用RETURNING INTO报语法错误从网上抄了一段PostgreSQL的存储过程代码里面写了INSERT INTO ... RETURNING id INTO v_id;在openGauss上执行直接报syntax error at or near INTO。原因openGauss虽然基于PostgreSQL内核但RETURNING INTO这个语法在全版本里支持和兼容情况不一有些环境会把它当成非法表达式。实验和课设场景里完全可以用更稳妥的两步走先SELECT取序列值或当前值再做插入。解决换成先取后插的写法。比如要拿到新插入的book_id先SELECT nextval(book_book_id_seq) INTO v_id;然后插入时显式指定book_id。这种写法在openGauss上全版本兼容也更好读。血泪经验就是实验代码优先保证在平台上能跑再去追求语法简洁。5.4 现象建表时写了Book大写表名查询时book提示不存在建表语句是CREATE TABLE Book (...)查询时用SELECT * FROM book;报错说关系不存在。用\d查看时表名变成了小写book。原因openGauss对不带双引号的标识符自动转成小写存储这是PostgreSQL系数据库的默认行为。MySQL里表名大小写敏感PostgreSQL系里大小写不敏感但全部转为小写。真正要区分大小写必须给标识符加双引号CREATE TABLE Book但这样以后每次查询都得带双引号非常痛苦。解决统一用小写命名。建表和所有查询都把表名、字段名写成小写避免后续在Java或Python代码里拼SQL时大小写不一致导致运行时错误。这件事优先级很高因为课设阶段往往是代码里拼SQL报错时定位到大小写问题最浪费时间。5.5 现象课设验收时助教反馈查询很慢或数据量一大就超时功能都做完了但课设里有个报表查询数据量几千条时还行几万条就卡好几秒。助教看完直接说性能分要扣。原因多表JOIN的关联字段没建索引或者WHERE条件里对字段做了隐式类型转换导致索引失效。还有一种常见原因是查询里写了SELECT *把所有字段都捞出来网络和磁盘开销全浪费了。解决给所有外键字段补上索引比如borrow表的sno和book_idWHERE条件里保证字段类型和传参类型一致避免数字当字符串传把SELECT *改成只查需要的字段。做完这三步大多数慢查询都能有立竿见影的改善。从那以后我每次交课设前都强制自己把每个JOIN字段逐个查一遍索引这习惯救了我很多次数据库答辩。希望帮到你。6. 数据库课程设计从建表脚本到答辩材料的完整落地6.1 课设选型和工程结构别只写SQL要搭一个能跑的项目广工数据库课设一般要求做一个完整的小系统图书管理、学生选课、商品订单是三个最经典的选题。选型时优先选自己熟悉的业务因为业务熟悉程度直接决定ER图和数据字典的质量。工程结构上我一般会分三个目录sql放全部建表和存储过程脚本docs放ER图、数据字典和实验报告src放后端代码和前端页面。这样提交压缩包的时候助教一眼就能找到他要看的东西。6.2 一个可复用的课设脚本清单db_course_design/ ├── sql/ │ ├── 01_create_tables.sql │ ├── 02_init_data.sql │ └── 03_store_procedures.sql ├── docs/ │ ├── ER图.png │ ├── 数据字典.xlsx │ └── 实验报告.docx └── src/ ├── backend/ └── frontend/这套结构的核心思路是脚本按执行顺序编号01_create_tables.sql只放建表语句02_init_data.sql只放INSERT数据03_store_procedures.sql放存储过程和触发器。初始化数据脚本里每张表至少放5到10条测试数据因为答辩时老师一定会当场执行查询数据太少看不出效果。数据字典用Excel整理每张表一个sheet列出字段名、类型、约束、说明这比在Word里写一大段文字直观得多。6.3 答辩前的自查清单交课设前我会强制走一遍清单所有sql脚本能否从头到尾执行成功每个查询是否按WHERE条件命中索引存储过程的异常处理是否真实生效——故意传一个不存在的ID测试会不会抛错外键约束是否阻止了非法数据插入。最后把登录页和核心查询页面截图放进实验报告里图比文字有力得多。这条路径走完答辩基本稳了。希望帮到你。本文还有配套的精品资源点击获取
