news 2026/9/25 3:57:31

openGauss数据库实验全攻略:从环境搭建到课设答辩

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
openGauss数据库实验全攻略:从环境搭建到课设答辩

简介:面向广东工业大学数据库课程的一套实验与课设资料,以openGauss实验平台为主线,并配有一个JDBC课设项目,适合正在做实验报告或需要参考数据库课设代码的学生。实验部分覆盖基本表建立、查询、索引与视图、存储过程、触发器五个环节,每项都给出了可运行的代码和相关说明,能帮助对照openGauss的语法特点完成实验。课设部分是一个Java项目,包含Java源码、class编译产物、mysql-connector-java驱动和运行截图,演示了通过JDBC连接数据库并执行操作的完整流程,日志文件也便于排查问题。压缩包共64个文件,主要类型为Java源码和class文件,另外有xml配置、图片、jar驱动、log日志等,整体大小6.93MB,目录按源码、编译、配置和图片分开,查找方便。已有2930人学习下载,对同校学生来说,既能借鉴实验思路,也能直接利用课设代码,是完成数据库课程任务的高效参考。

1. openGauss成为广工数据库实验平台:不只是换一个安装包那么简单

数据库实验在广工的课程体系里是一项需要写报告、答辩并留档的硬任务,近年以openGauss作为实验平台之后,学生首先要面对的是:安装不再靠“下一步下一步”,而是一整套用户、目录、权限、初始化参数的操作链;存储过程、触发器、事务隔离这些原本只出现在试卷里的考点,也变成了必须在命令行里亲手跑出来的结果。这篇笔记不按实验题号逐条讲,只围绕“2022年广工数据库实验+openGauss+课设”这条主线,把从零搭建实验环境、完成常见实验、写完课程设计并顺利答辩的路径走一遍。适合正在被实验报告和课设两头夹击的同学,也适合带实验的助教参考。

2. 本地搭建openGauss实验环境:从依赖、用户、初始化到gsql能跑通

2.1 为什么不要用root装,实验前先建一个专属用户

openGauss的安装脚本一直坚持:不能用root直接跑。这不是玄学,而是数据库实例一旦以root启动,数据目录和日志文件的属主就难以约束,后续任何一处权限放得过宽都会成为隐患。实验机通常是自己一个人用,很多同学图省事直接在主目录解压,结果预安装脚本第一步就退出。常见做法是先新建一个专用系统用户,例如omm,同时建好同名组dbgrp:

# 建组和用户,后面所有安装操作都用 omm 执行 groupadd dbgrp useradd -m -g dbgrp omm echo 'Lab_2022_pass' | passwd --stdin omm

参数说明:-m表示创建用户主目录,-g指定初始用户组。这里把窗口期需要的实验密码写成了“Lab_2022_pass”,你可以换成自己的,但建议只用字母数字加下划线,避免特殊符号在后续命令行里总是要转义。第二步是把openGauss的环境变量写进omm的bash配置:

echo "export GAUSSHOME=/opt/software/openGauss/app" >> /home/omm/.bashrc echo "export PATH=\$GAUSSHOME/bin:\$PATH" >> /home/omm/.bashrc echo "export LD_LIBRARY_PATH=\$GAUSSHOME/lib:\$LD_LIBRARY_PATH" >> /home/omm/.bashrc source /home/omm/.bashrc

这一段的意义在于:不配置PATH,gsql、gs_ctl这些命令根本找不到,安装完以后连“gsql不是内部或外部命令”这种低级报错都排查半天。实验环境刚搭时,我一般会把这三行当成固定动作,先配好再继续。

2.2 下载解压与配置文件:cluster_config.xml里最容易错的两个参数

到openGauss官方网站,按操作系统和架构下载对应版本的企业版或轻量版安装包,实验电脑建议用CentOS 7.6及以上或openEuler虚拟机,资源不低于2核4GB,内存不够的话gs_install阶段容易被OOM杀掉。下载后解压:

# 切换到 omm 用户,目录统一放在 /opt/software 下 su - omm mkdir -p /opt/software/openGauss cd /opt/software/openGauss tar -zxvf /your_download_path/openGauss-x.x.x-CentOS-64bit.tar.gz

解压后根目录下会有gs_preinstall、gs_install两个脚本和一个cluster_config.xml模板。单机实验只需要把cluster_config.xml里的节点名改对。最容易翻车的两个参数是nodeNames和DEVICE里的name:这两个值必须和系统的hostname一致,而不是随便取一个“db1”。检查hostname用命令hostname,不要让它返回localhost.localdomain。配置文件修改后大致是这样:

<?xml version="1.0" encoding="UTF-8"?> <ROOT> <CLUSTER> <PARAM name="clusterName" value="dbCluster"/> <PARAM name="nodeNames" value="opengauss01"/> <PARAM name="gaussdbAppHome" value="/opt/software/openGauss/app"/> <PARAM name="gaussdbLogHome" value="/opt/software/openGauss/log"/> <PARAM name="tmpMoc" value="/tmp"/> <PARAM name="gaussdbToolPath" value="/opt/software/openGauss/tool"/> <PARAM name="corePath" value="/opt/software/openGauss/corefile"/> </CLUSTER> <DEVICELIST> <DEVICE sn="1000001"> <PARAM name="name" value="opengauss01"/> <PARAM name="azName" value="AZ1"/> <PARAM name="azPriority" value="1"/> <PARAM name="backIp1" value="192.168.1.11"/> </DEVICE> </DEVICELIST> </ROOT>

参数说明:nodeNames与DEVICE的name必须等于hostname输出;backIp1填本机内网或虚拟机NAT的IP。如果虚拟机用NAT模式,IP没固定,建议先在虚拟机设置里改成静态IP或DHCP保留,否则重启后IP漂移,找半天原因。

2.3 预安装与初始化:一次跑完最少踩两个坑

预安装脚本的作用是检查依赖、初始化运行环境、做目录规划。常见做法是全自动模式:

cd /opt/software/openGauss ./gs_preinstall -U omm -G dbgrp -X /opt/software/openGauss/cluster_config.xml --non-interactive

参数说明:-U指定运行用户,-G指定用户组,-X指定配置文件,--non-interactive跳过交互问答。预安装阶段如果报缺libaio-devel、flex、bison,先补齐再重跑:yum -y install libaio-devel flex bison python3。缺依赖硬跑,后面gs_install会以“初始化数据库失败”这种模糊话术崩掉,特别浪费时间。

预安装成功后执行初始化:

./gs_install -X /opt/software/openGauss/cluster_config.xml

这一步会初始化数据目录、生成postgresql.conf和pg_hba.conf、设置初始用户omm的密码。初始化完成后,启动单机实例并检查状态:

gs_ctl start -Z single_node -D /gaussdb/data gs_ctl status -Z single_node -D /gaussdb/data

-Z single_node表示部署形态为单节点,-D指向gs_install输出中显示的数据目录,通常为/gaussdb/data。看到“online”状态就说明实例起来了。然后第一件事是用gsql登录默认数据库postgres:

gsql -d postgres -U omm -h 127.0.0.1 -p 5432 -W

参数说明:-d指定数据库名,-U指定用户名,-h指定监听地址,-p指定端口号,openGauss默认端口是5432,-W表示交互输入密码。连不上时先看gs_ctl status,再看5432端口是否有监听:ss -lntp | grep 5432。这一步能过滤出八成安装问题。

2.4 建实验库和实验账号:分清系统库和你自己要用的库

默认只有一个postgres库,所有实验都堆在里面,后面做权限实验时会互相干扰。我一般会在第一周实验就固定好一套命名:

CREATE DATABASE labdb ENCODING 'UTF8' TEMPLATE template0; CREATE USER lab_user WITH PASSWORD 'Lab_123456'; GRANT ALL PRIVILEGES ON DATABASE labdb TO lab_user;

参数说明:ENCODING显式写成UTF8,并且用TEMPLATE template0,是因为template1的默认编码不一定是UTF8,直接建库容易得到中文乱码。GRANT ALL PRIVILEGES只授权到数据库级别,模式级别的授权后面做权限实验时再单独练。至此,实验环境已经能跑起来,下一步进入实验本身的拆解。

3. 数据库实验的四个必考层次:建表、增删改查、视图与事务的落地写法

3.1 建表与约束:主键、外键、CHECK约束各自的实验目的

广工数据库实验的第一个层次围绕表结构设计。不是拿一个CREATE TABLE模板复制就完事,重点是每种约束要解释清楚为什么存在。历年实验任务里出现频率最高的就是学生、课程、成绩三张表,一个能直接跑的表结构:

CREATE TABLE students ( sid CHAR(8) PRIMARY KEY, name VARCHAR(32) NOT NULL, dept VARCHAR(64) DEFAULT '计算机学院', grade INT CHECK (grade BETWEEN 2000 AND 2050) ); CREATE TABLE courses ( cid CHAR(8) PRIMARY KEY, cname VARCHAR(64) NOT NULL, credit NUMERIC(2,1) CHECK (credit > 0 AND credit <= 10) ); CREATE TABLE sc ( sid CHAR(8), cid CHAR(8), score NUMERIC(5,1) CHECK (score >= 0 AND score <= 100), PRIMARY KEY (sid, cid), FOREIGN KEY (sid) REFERENCES students(sid) ON DELETE CASCADE, FOREIGN KEY (cid) REFERENCES courses(cid) ON DELETE CASCADE );

逻辑说明:PRIMARY KEY既是实体唯一标识,也是查询的入口,openGauss建主键时会自动建唯一索引;CHECK约束把非法数据挡在数据库层之外。外键的ON DELETE CASCADE是高频考点——如果不指定ON DELETE,外键默认动作会阻止删除被引用的行,实验报告里要把CASCADE和RESTRICT的差别讲清楚。

注意,主键在单机部署下生成btree索引,将来如果接触分布式部署,表还要考虑分布列,实验阶段不用管。

3.2 DML增删改查:批量插入、UPDATE子查询和分组统计的写法差异

第二个层次是DML。很多课设只做到“单表插入、单表查询”的程度,太浅。课堂实验想拿高分,至少要写批量插入:

INSERT INTO courses (cid, cname, credit) VALUES ('C001', '数据库原理', 3.0), ('C002', '操作系统', 3.5), ('C003', '计算机网络', 2.5);

批量插入比逐行INSERT的优势不只是语句短,多条VALUES在一条语句内是原子性的,要么全部插入,要么全部回滚,这个特性在实验报告里值得写一笔。大规模造数据可以配合generate_series,把学生表扩到几百行:

INSERT INTO students (sid, name, dept, grade) SELECT '2022' || lpad(i::text, 4, '0'), '测试学生' || i, '计算机学院', 2022 FROM generate_series(1, 200) i;

这里的lpad函数把数字i补成四位,再拼上前缀“2022”,得到“20220001”这种定长学号,避免主键不统一。

UPDATE带子查询也是实验爱考的写法,比如把所有平均分低于60的学生成绩提到60:

UPDATE sc SET score = 60 WHERE sid IN ( SELECT sid FROM ( SELECT sid, AVG(score) avg_score FROM sc GROUP BY sid HAVING AVG(score) < 60 ) t );

子查询套在UPDATE的条件里,是openGauss和PostgreSQL风格的标准解法。分组统计更是必考,尤其注意GROUP BY和HAVING的分工:

SELECT s.dept, c.cid, COUNT(*) AS cnt, ROUND(AVG(sc.score),2) AS avg_score FROM students s JOIN sc ON s.sid = sc.sid JOIN courses c ON sc.cid = c.cid WHERE c.credit >= 2.5 GROUP BY s.dept, c.cid HAVING COUNT(*) >= 10 ORDER BY avg_score DESC;

GROUP BY的列必须和SELECT里的非聚合列严格一致,这是数据库原理课扣分最狠的地方;HAVING里过滤的是聚合后的结果,WHERE过滤的是原始行——这两个区别每学期都有人搞反。

3.3 视图与索引:这对实验要展示的是“为什么调优不是玄学”

第三层次常见任务是创建视图和索引,再做执行计划对比。视图侧重点在于看出它不占物理存储:

CREATE VIEW v_score_overview AS SELECT s.sid, s.name, s.dept, c.cname, sc.score FROM students s LEFT JOIN sc ON s.sid = sc.sid LEFT JOIN courses c ON sc.cid = c.cid;

视图本质是保存一段SQL定义,不是复制数据。实验报告里要强调“基表数据变化时视图内容实时跟着变”,这是它与物化视图的核心区别。

索引部分最好用EXPLAIN ANALYZE验证,先看没索引的情况,再建索引:

EXPLAIN ANALYZE SELECT * FROM sc WHERE cid = 'C001'; CREATE INDEX idx_sc_cid ON sc(cid); EXPLAIN ANALYZE SELECT * FROM sc WHERE cid = 'C001';

第一次执行计划是Seq Scan,建索引后变成Index Scan或Bitmap Index Scan。实验报告里把两次执行计划中“actual time”的差距贴出来,比空写“索引能加速查询”有说服力得多。还需要说明一个观察结论:数据量只有几百行时,优化器可能放弃索引走全表扫描;数据量几万行时索引优势才明显。

3.4 事务与并发:两个gsql窗口能说明隔离级别的大部分问题

第四层次是事务。实验机开两个终端,一个终端begin,另一个终端查询,最能体现隔离级别:

-- 终端A BEGIN; UPDATE sc SET score = score + 1 WHERE sid = '20220001'; -- 终端B SELECT * FROM sc WHERE sid = '20220001';

逻辑说明:终端A更新但不提交,终端B的SELECT会被阻塞住,这是行级锁的正常表现,不是系统卡死。接着把事务隔离级别设置为可重复读,观察快照差异:

BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; SELECT * FROM sc WHERE sid = '20220001';

openGauss默认隔离级别是读已提交,每条语句取最新快照;可重复读下,整个事务使用同一快照,所以事务开始后其他会话提交的数据看不到。实验报告里把这两个级别在同一个业务场景下的表现对比清楚,事务这一章就稳了。注意,不要在终端A事务未提交时又在同一窗口里把事务改成其他模式,自锁会把自己卡死。

4. openGauss存储过程与触发器:从MySQL习惯迁移过来的三个关键差别

4.1 为什么openGauss的存储过程和MySQL不是一回事

很多同学先在MySQL里写了存储过程,再来openGauss里交实验,最容易踩的坑就是把MySQL的DELIMITER习惯带过来。在MySQL里必须用DELIMITER把分号冲突绕开,但openGauss的SQL解析器对CREATE FUNCTION和CREATE PROCEDURE是整体处理的,函数体内直接写BEGIN END,每条语句以分号结束不会被提前执行。所以在openGauss里写“DELIMITER $$”,反而直接报语法错误。

第二个关键差别是过程语言。openGauss与PostgreSQL同源,过程语言是PL/pgSQL,赋值用“:=”或SELECT INTO,日志输出用RAISE NOTICE,异常抛出用RAISE EXCEPTION。第三个差别是返回方式:函数必须有RETURNS类型声明,存储过程则用IN/OUT参数来交换结果。这些差别整理成一张表,实验报告可以直接参考:

对比点MySQL 存储过程openGauss 存储过程
定界符DELIMITER $$不需要,直接CREATE
赋值方式SET var = ...var := ... / SELECT INTO
日志输出SELECT 'text'RAISE NOTICE 'text'
抛异常SIGNAL SQLSTATERAISE EXCEPTION
条件/循环IF...END IF、LOOP...END LOOP关键字基本一致

4.2 出题频率最高的函数:按系部统计平均分

一个能作为实验作业直接提交的函数是:输入系部名,返回该系学生的选课平均分,同时用COALESCE处理没有成绩数据的情况。可执行版本如下:

CREATE OR REPLACE FUNCTION dept_avg_score(dept_name IN VARCHAR) RETURNS NUMERIC(5,1) LANGUAGE plpgsql AS $$ DECLARE v_avg NUMERIC(5,1); BEGIN SELECT ROUND(AVG(sc.score),1) INTO v_avg FROM sc JOIN students s ON sc.sid = s.sid WHERE s.dept = dept_name; IF v_avg IS NULL THEN RAISE NOTICE '该系暂无选课成绩'; RETURN 0; END IF; RETURN v_avg; END; $$;

逻辑说明:INTO子句是PL/pgSQL的关键赋值方式,把SELECT结果写进变量。如果查询返回多行,PL/pgSQL会直接报错,因此这里必须先聚合保证只有一行返回。RAISE NOTICE是openGauss的控制台输出手段,实验报告里建议把“用SELECT打印日志”的习惯改掉。

参数说明:dept_name IN VARCHAR定义了输入参数,调用时传入系名;RETURNS NUMERIC(5,1)声明返回类型;RETURN 0把NULL转成0,避免前端拿到空值还要判空。调用时直接:

SELECT dept_avg_score('计算机学院');

4.3 触发器:BEFORE UPDATE日志表的完整套路

触发器实验第一步是建日志表,记录成绩表的改动,然后写触发器函数和触发器本身:

CREATE TABLE sc_log ( log_id BIGSERIAL PRIMARY KEY, sid CHAR(8), cid CHAR(8), old_score NUMERIC(5,1), new_score NUMERIC(5,1), op_type VARCHAR(8), op_time TIMESTAMP DEFAULT current_timestamp ); CREATE OR REPLACE FUNCTION trg_fn_sc_update_log() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN INSERT INTO sc_log(sid, cid, old_score, new_score, op_type) VALUES (NEW.sid, NEW.cid, OLD.score, NEW.score, 'UPDATE'); RETURN NEW; END; $$; CREATE TRIGGER trg_sc_update_log BEFORE UPDATE ON sc FOR EACH ROW EXECUTE FUNCTION trg_fn_sc_update_log();

逻辑说明:BEFORE UPDATE使触发器在数据修改前执行;INSERT操作时只有NEW记录,UPDATE操作时NEW和OLD同时存在;RETURN NEW表示让原修改继续执行,如果把RETURN NEW改成RETURN NULL,原UPDATE会被取消。FOR EACH ROW是行级触发器——实验里如果误写成FOR EACH STATEMENT,一条UPDATE只触发一次,日志表里只会出现一条记录,很多人检查日志发现数量不对,问题就出在这里。

验证触发器是否生效:

UPDATE sc SET score = score + 1 WHERE sid = '20220001'; SELECT * FROM sc_log;

注意,即使UPDATE把score加0,行数据没有实际变化,只要行被更新,行级触发器也会激活,日志表会多一行冗余记录。想避免这个现象,可以在函数里加一个IF NEW.score IS DISTINCT FROM OLD.score的判断,这属于加分项。老版本里触发器的EXECUTE FUNCTION写法需要改成EXECUTE PROCEDURE,按实际安装版本的兼容提示调整即可。

5. 实验与课设路上绕不过去:openGauss安装与使用中的五类报错排查

5.1 预安装脚本在check OS version时退出:主机名解析的锅

现象:执行gs_preinstall时,还没进入依赖检查就报“Checking OS version... failed”,或直接报权限类错误。

原因:脚本会解析cluster_config.xml里的nodeNames,再用hostname命令得到的机器名去/etc/hosts里做解析。很多实验机的机器名是localhost.localdomain,或者hosts里没有把IP和机器名关联在一起,解析失败就退出了。

解决:先把hostname改成一个唯一标识,再编辑hosts文件:

hostnamectl set-hostname opengauss01 vi /etc/hosts

在hosts里追加一行,把本机IP和主机名对应起来,例如“192.168.1.11 opengauss01”。改完重新登录确认hostname已经生效,再重跑预安装。这是安装阶段最常见的翻车点,先查这一条能救回半小时。

5.2 gsql用127.0.0.1连不上:pg_hba.conf默认没有放行TCP

现象:gs_ctl status显示实例已online,但gsql -h 127.0.0.1连接时报“FATAL: no pg_hba.conf entry for host '127.0.0.1'”。

原因:openGauss初始化后的pg_hba.conf默认只允许本机Unix socket访问,TCP连接需要显式授权。很多同学习惯用localhost,表面看都是本机,但TCP走的是独立认证条目,没有放行就拒绝连接。

解决:编辑数据目录下的pg_hba.conf,加上两行:

host all all 127.0.0.1/32 sha256 host all all 192.168.1.0/24 sha256

保存后用gs_ctl reload让配置生效。注意,不要为图方便改成trust认证,哪怕是实验环境也别交这种报告,数据库安全章节里认证方式对比就彻底没法写了。

5.3 gsql里中文变成乱码:client_encoding和server不一致

现象:向表里插入‘计算机学院’,查出来变成“¤Æ”或类似的乱码。

原因:服务端数据库字符集是UTF8,客户端工具默认使用操作系统locale,比如LANG=zh_CN.GB18030,两边编码不一致,写入和读取都错位。

解决:在gsql里执行SET client_encoding TO 'UTF8';,或者在启动gsql之前先设置环境变量:

export PGCLIENTENCODING=UTF8

这个坑很容易被误写成“openGauss对中文支持不好”,实际是客户端编码没对齐。做实验时把客户端固定成UTF8,中文相关的实验就不会再出幺蛾子。

5.4 普通用户建表报permission denied for schema public:授权只给到数据库不够

现象:用lab_user连接labdb后执行CREATE TABLE,报“permission denied for schema public”。

原因:在openGauss里,public schema的可写权限默认不向普通用户开放。很多实验手册只写了CREATE USER和GRANT ALL PRIVILEGES ON DATABASE,但这个授权并不包含schema级的写权限。

解决:用omm管理员在labdb里执行:

GRANT CREATE, USAGE ON SCHEMA public TO lab_user;

这行授权要和建库时的GRANT区分开:一个是数据库级权限,一个是模式级权限。实验报告里把这两个层级分别写清楚,权限章节的分不会低。如果不想开放public,也可以让lab_user建自己的schema再设置search_path,但课设时间紧张时别折腾这个。

5.5 DROP DATABASE总是失败:还有活动连接占着库

现象:执行DROP DATABASE labdb,报“database 'labdb' is being accessed by other users”。

原因:自己或助教在另一个窗口开着连到labdb的会话,openGauss不会在DROP时自动断开所有连接,必须手动终止。

解决:先查占用连接并终止,再删库:

SELECT pid, usename, application_name, state FROM pg_stat_activity WHERE datname = 'labdb'; SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'labdb' AND pid <> pg_backend_pid(); DROP DATABASE labdb;

注意,第二条一定要带pid <> pg_backend_pid(),否则连自己执行命令的会话也kill掉了,DROP会跟着断开。这是比较典型但很尴尬的低级错误,排查顺序记牢:先查连接,再终止,最后删。

6. 课程设计怎么从“能跑”到“能答辩”:一个可复用的学生选课项目样板

课设题目五花八门,但评审最看重的就三件事:表结构有没有冗余、事务和存储过程有没有真实场景、性能分析是不是自己跑出来的。我一般建议用“学生选课+成绩分析”作为载体,体量不大,但能把数据库课程的考点全部带出来。

选题后按四个步骤搭:第一步,关系模式落地,学生表、课程表、选课表之外,加一个院系表消掉students表里的冗余字段,所有外键按逻辑加上,答辩时被问实体完整性和参照完整性就不慌;第二步,存储过程用真实业务,比如按系部统计平均成绩,把第4章的dept_avg_score原样扩展成“补考名单统计”;第三步,触发器放在成绩表上,做成绩修改自动写日志,演示时直接UPDATE一行再查sc_log;第四步,性能验证用数据说话,把选课表扩到几万行,在有无索引下各跑一次EXPLAIN ANALYZE,打印两张执行计划,把“actual time”的差值写进PPT。

答辩验证建议准备一张自检表:

维度演示内容必说出口的术语
表设计ER图到关系模式转换范式、主外键、引用完整性
事务两个gsql窗口同时改数据原子性、读已提交、锁
存储过程CALL一次带参数的过程IN参数、RAISE NOTICE
触发器UPDATE后查日志表ROW级触发、NEW/OLD
性能索引前后EXPLAIN对比Seq Scan、Index Scan、执行计划

最后给自己留一句“技术边界”的话:单机部署只能演示锁等待和隔离级别观察,做不了真正的分布式扩展。这不算扣分项,反而能显示你清楚实验平台边界。

做了几年实验指导后,我把一个习惯带进了所有数据库实践:每次在openGauss里操作前先想清楚要不要包事务,出问题回滚得比删数据快;每次写存储过程都顺手加一条RAISE NOTICE输出,排错时少很多黑盒猜测;每次建索引都要跑EXPLAIN验证效果再收工。这三个习惯帮我少踩了很多坑,希望帮到你。

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

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

AI Coding 前移:用 OpenSpec 实现需求到接口的契约驱动开发

1. 项目概述&#xff1a;为什么把“写代码”这件事往后挪了一步&#xff1f;“我把 AI Coding 的决策移到了写代码之前”——这句话刚在内部技术分享会上说出来&#xff0c;就有同事笑着问&#xff1a;“代码都不写了&#xff0c;那还叫开发吗&#xff1f;”其实恰恰相反&#…

作者头像 李华
网站建设 2026/9/25 3:50:13

RTSP转HLS实战:FFmpeg+Nginx+SSM实现浏览器监控播放

简介&#xff1a;本资源面向Java后端初学者与流媒体实时预览需求者&#xff0c;提供一套基于SSM架构、Nginx与FFmpeg将RTSP流转换为HLS流并在前端HTML播放的完整可运行方案&#xff0c;适用于视频监控、在线教育、直播等场景的入门实践。压缩包共52个文件&#xff0c;约70.26MB…

作者头像 李华
网站建设 2026/9/25 3:48:34

CTF实战写作规范:为何虚构赛事不能写实操指南

我无法基于“2026年第一届创宇网络安全技能大赛”这一标题生成符合要求的博文内容。原因如下&#xff1a;该标题指向一个尚未举办的、虚构或预告性质的赛事活动&#xff0c;不构成可实操、可复现、可深度拆解的技术项目。根据您设定的核心创作原则&#xff1a;所有内容必须“忠…

作者头像 李华