Oracle 11g 实例源程序跑通:建库脚本、执行顺序与 PL/SQL 排错

发布时间:2026/11/4 12:50:44
Oracle 11g 实例源程序跑通:建库脚本、执行顺序与 PL/SQL 排错

简介:《Oracle 11g从入门到精通(第二版)》配套实例源程序压缩包,面向数据库初学者、DBA及备考Oracle相关认证的读者,用于把安装配置、SQL查询、表与索引、视图、存储过程、触发器、用户权限、备份恢复、SQL调优、分区与并行执行等章节知识落到可运行案例中。包内共495个文件,以txt实验说明与脚本、java和class示例代码、xml配置、jpg操作截图、bak备份及doc/xls辅助文档为主,整体约1.21MB,目录按章节组织,便于按主题检索和复现。已有405人学习下载。读者可对照每章案例完成建库建表、编写SQL、调试存储过程与触发器、模拟备份恢复和性能调优,并借助备份与配置文件理解实验环境搭建与排错思路,适合作为课程配套练习和日常查阅的案例库,尤其适合需要边学边练、按章节查漏补缺的读者,从基础概念到分布式系统、XML支持和数据仓库等高级主题均有对应练习线索。

1. 从一份压缩包开始的 Oracle 11g 练习环境

很多人拿到《Oracle 11g 从入门到精通(第二版)》的配套实例源程序,第一反应是解压完不知道从哪个文件下手——书里讲的建表、序列、存储过程散在十几章,脚本文件名又大多是拼音缩写,双击打开一堆CREATE TABLE看得头皮发麻。这份源程序的实际价值,是把书里零散的示例收拢成一套有执行顺序的脚本集合:先建表空间,再建用户,再跑建表和造数脚本,最后编译 PL/SQL 对象,按这个顺序喂给数据库,你手上就多了一个和书里一致的、可以随便删表随便造数据的沙箱库。它适合两类人:刚接触 Oracle、需要个能反复推倒重来的练习库的新手;以及做内部培训、不想花两天造演示数据的开发。核心词就一个——实例源程序,它是“能跑起来”的前提,不是单纯给你抄 SQL 的文本。

2. 资源构成与目录结构:一份配套源程序里到底装了什么

解压之后不要急着找.sql双击,先花十分钟把包里的文件按类型归类。配套源程序这种东西通常不是单一工程,而是“书稿里每一章的示例 + 一份公共建库脚本 + 若干数据文件”的混合体,能不能顺利跑通,八成取决于你有没有先认清哪些文件是地基、哪些是装修。

2.1 四类文件先分清,别混着跑

我拆过的这类包里,文件大致落在四个格子里,处理方式完全不同:

文件类型常见扩展名作用处理方式
建库/建用户脚本.sql表空间、用户、权限、目录对象最先跑,只跑一次
表结构与数据脚本.sqlDDL + INSERT,按章分文件按编号顺序跑
PL/SQL 对象脚本.sql/.prc/.pck存储过程、函数、触发器、包表建完之后编译
导出文件与说明.dmp/.txt/.doc整库快照、执行说明、字段对照二选一,别和 SQL 脚本重复导入

最容易踩的一个坑是把.dmp和.sql混着用:先用impdp导了一遍,又跑一遍建表脚本,结果满屏ORA-00955: 名称已由现有对象使用。我的习惯是二选一,优先走.sql脚本——因为脚本可读、可改、可以只跑某一章;.dmp只在脚本缺失或者数据量特别大的时候用。

2.2 目录怎么读:从建库脚本到章节示例的映射

包里的目录结构大同小异,典型长这样:

oracle11g_src/ ├── 00_setup/ │ ├── 01_tablespace.sql -- 建表空间 │ ├── 02_user_grant.sql -- 建用户 + 授权 │ └── 03_directory.sql -- 建 DIRECTORY 对象(导入导出用) ├── 01_basic/ │ ├── ch02_table.sql -- 第2章 表与约束 │ ├── ch03_data.sql -- 第3章 数据操作 │ └── ch04_query.sql -- 第4章 查询示例 ├── 02_advanced/ │ ├── ch08_view_index.sql │ ├── ch09_plsql_basic.sql │ └── ch10_procedure.sql ├── 03_project/ │ ├── create_all.sql -- 综合案例建表 │ ├── init_data.sql -- 综合案例造数 │ └── pkg_*.sql -- 综合案例的包与过程 └── readme.txt

读这份目录的关键是认前缀:00_开头的是地基,任何情况下都先跑;01_是跟着书走的基础章节,可以挑着跑;02_涉及视图、索引、PL/SQL,必须在表和数据到位之后;03_是综合案例,脚本之间互相引用,缺一个就编译不过。

如果你手上这份包的目录是扁平的一堆ch01.sql到ch15.sql,也不用慌,先打开每个文件头部看注释——好的配套脚本会在开头写明“依赖:需先执行 ch02_table.sql”。

2.3 执行顺序与依赖关系,别信文件名排序

文件名排序不等于执行顺序。真正的依赖链是这样的:

表空间 → 用户与权限 → 基础表 → 约束与索引 → 初始数据 → 视图 → 序列 → 触发器 → 存储过程/函数 → 包 → 定时作业

触发器排在序列后面,是因为很多示例触发器要引用序列的NEXTVAL;包排在过程后面,是因为包体里会调用独立过程。顺序错了不会立刻报错,但会在编译阶段给你一堆PLS-00201: 必须声明标识符,然后你花两小时去查一个根本不存在的语法问题。

稳妥的做法是自己写一个总控脚本run_all.sql,用@@相对路径串起来:

-- run_all.sql 放在包根目录,用 SQL*Plus 执行 SET DEFINE OFF SET SERVEROUTPUT ON SIZE UNLIMITED SET ECHO OFF WHENEVER SQLERROR CONTINUE @@00_setup/01_tablespace.sql @@00_setup/02_user_grant.sql @@01_basic/ch02_table.sql @@01_basic/ch03_data.sql @@02_advanced/ch08_view_index.sql @@02_advanced/ch09_plsql_basic.sql @@03_project/create_all.sql @@03_project/init_data.sql PROMPT ==== all scripts done, check spool log ====

几处参数值得说清楚:SET DEFINE OFF关掉&替换变量,否则脚本里只要出现一个&字符(比如字符串里的“A&B”),SQLPlus 就会弹出输入框等你填值,批量执行直接卡死;WHENEVER SQLERROR CONTINUE让报错后继续往下跑而不是中断,便于一次性看到所有问题,代价是你要认真读日志;@@和@的区别是前者以当前脚本所在目录为基准解析相对路径,后者以 SQLPlus 启动目录为基准——写成@的话,换个目录执行就全找不到文件。

3. 环境落地:把 11g 实例库跑起来的完整步骤

脚本本身不会自己跑,得先有个能接住它的库。这一章按“装库 → 建地基 → 跑脚本 → 验数据”四步走,中间穿插几个必须提前定下来的参数,定错了后面改起来很麻烦。

3.1 装库之前先定三件事:字符集、内存、归档

字符集是最容易后悔的一项。建库时选ZHS16GBK,后面接一个 UTF-8 的应用,中文就变成问号;选AL32UTF8,某些老系统的 GBK 数据导进来又是乱码。我的默认建议是新库一律AL32UTF8,理由不是它更“先进”,而是它的超集特性让 GBK 数据进来能存住、出去能转回来,而反方向不行。

内存按机器来,11g 的自动内存管理已经比较成熟:

-- 建库后调整内存参数,示例:16G 内存的测试机 ALTER SYSTEM SET memory_target = 6G SCOPE=SPFILE; ALTER SYSTEM SET memory_max_target = 6G SCOPE=SPFILE; -- 如果不用 AMM,改走 ASMM -- ALTER SYSTEM SET sga_target = 4G SCOPE=SPFILE; -- ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=SPFILE;

改完必须重启实例才生效,SCOPE=SPFILE意味着写进参数文件、当前实例不动。这里顺手踩过一个坑:memory_target设得比物理内存还大,实例起不来,报ORA-00845: MEMORY_TARGET not supported on this system——本质是/dev/shm空间不够,测试机把共享内存调大或者干脆改用 ASMM 就行。

归档模式看你干什么用。纯粹跑书上的示例脚本,不开归档也能跑;但只要涉及闪回查询、闪回表、RMAN 备份练习这些 11g 的招牌功能,就必须开:

SHUTDOWN IMMEDIATE; STARTUP MOUNT; ALTER DATABASE ARCHIVELOG; ALTER DATABASE OPEN; -- 验证 ARCHIVE LOG LIST;

3.2 建表空间与用户:示例脚本的地基

包里00_setup下的两个脚本基本是这个形状,我按常见写法补全一遍,方便你对照改:

-- 01_tablespace.sql CREATE TABLESPACE demo_data DATAFILE '/u01/app/oracle/oradata/orcl/demo_data01.dbf' SIZE 200M AUTOEXTEND ON NEXT 50M MAXSIZE 4G EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO; CREATE TEMPORARY TABLESPACE demo_temp TEMPFILE '/u01/app/oracle/oradata/orcl/demo_temp01.dbf' SIZE 100M AUTOEXTEND ON NEXT 20M MAXSIZE 2G;

EXTENT MANAGEMENT LOCAL和SEGMENT SPACE MANAGEMENT AUTO是 11g 下建表空间的事实标准,前者用位图管理区段分配,后者让段内空间自动管理,能明显减少碎片。唯一不要动的是SYSTEM、SYSAUX、UNDO、TEMP这四个系统表空间,示例脚本里如果出现修改它们的语句,直接注释掉。

用户和权限:

-- 02_user_grant.sql CREATE USER demo IDENTIFIED BY "Demo#2024" DEFAULT TABLESPACE demo_data TEMPORARY TABLESPACE demo_temp QUOTA UNLIMITED ON demo_data; GRANT CONNECT, RESOURCE TO demo; GRANT CREATE VIEW, CREATE SEQUENCE, CREATE TRIGGER, CREATE PROCEDURE, CREATE JOB TO demo; GRANT SELECT_CATALOG_ROLE TO demo;

QUOTA UNLIMITED ON demo_data这一行是新手最容易漏的。少了它,用户能建表但插不进数据,报ORA-01950: 对表空间 'DEMO_DATA' 无权限,而报错发生在 INSERT 的时候,很容易误以为是数据本身有问题。另外RESOURCE角色在 11g 里已经不含CREATE VIEW、CREATE JOB,所以还得单独授,别指望一个角色包打天下。

3.3 用 SQL*Plus 批量跑脚本的正确姿势

图形工具(SQL Developer、PL/SQL Developer)跑单章脚本很舒服,但批量执行我更信 SQL*Plus,因为它没有隐藏行为。命令行这样起:

# 本地实例,服务名 orcl sqlplus -S demo/"Demo#2024"@localhost:1521/orcl <<'EOF' SET DEFINE OFF SET SERVEROUTPUT ON SIZE UNLIMITED SPOOL run_$(date +%Y%m%d%H%M).log @run_all.sql SPOOL OFF EXIT EOF

拆开看几个细节。-S 是静默模式,去掉版本横幅,日志干净;SPOOL 把全过程写文件,出了问题先翻日志而不是凭记忆;SET SERVEROUTPUT ON SIZE UNLIMITED必须加,否则DBMS_OUTPUT.PUT_LINE一行都不输出,你会误以为存储过程没执行;heredoc 用<<'EOF'带单引号,防止 shell 先把$和反引号展开掉。

如果源程序里有中文,客户端还要设 NLS_LANG,不然日志里全是问号:

export NLS_LANG="AMERICAN_AMERICA.AL32UTF8"

这里的字符集部分要跟数据库一致;如果数据库是ZHS16GBK,就改成SIMPLIFIED CHINESE_CHINA.ZHS16GBK。设错了不会报错,只会默默把中文写成???,属于典型的不容易察觉的失败。

3.4 导入与校验:确认数据真的进去了

脚本跑完 log 里最后一行是==== all scripts done ====,不代表就成了。至少要过三关:

-- 第一关:对象计数,看建了多少张表 SELECT COUNT(*) FROM user_tables; -- 第二关:无效对象,编译失败的过程全在这儿 SELECT object_name, object_type, status FROM user_objects WHERE status = 'INVALID' ORDER BY object_type, object_name; -- 第三关:关键表的行数抽查 SELECT 'EMP' AS t, COUNT(*) FROM emp UNION ALL SELECT 'DEPT', COUNT(*) FROM dept;

第二关最关键。PL/SQL 脚本在 SQL*Plus 里编译失败默认不中断,会留一个INVALID状态的对象在那儿,后面调用时才炸。发现无效对象不用重跑全量,单独ALTER PROCEDURE p_xxx COMPILE;或者用DBMS_UTILITY.COMPILE_SCHEMA('DEMO')整体重编译,然后看USER_ERRORS视图里的具体报错行号。

如果包里有.dmp,走数据泵:

impdp demo/"Demo#2024"@localhost:1521/orcl \ directory=DEMO_DIR dumpfile=demo_full.dmp \ remap_schema=src_user:demo \ table_exists_action=replace \ logfile=impdp_demo.log

directory是数据库里的目录对象名,不是操作系统路径,得先在库里CREATE OR REPLACE DIRECTORY DEMO_DIR AS '/data/dump'建好并给用户读写权限。remap_schema用于把导出时的原 schema 换成本地用户,不加的话数据会尝试导进一个不存在的用户里。

4. 核心脚本拆解:从建表到 PL/SQL 的一条完整链路

地基搭好之后,真正值得读的是脚本里的设计写法。Oracle 11g 的配套示例通常有一条贯穿全书的小型业务案例,围绕它把表、约束、序列、触发器、过程、包串起来。下面按这条链路的顺序拆。

4.1 建表脚本里的约束与分区写法

看一个典型的订单表:

CREATE TABLE orders ( order_id NUMBER(12) NOT NULL, cust_id NUMBER(10) NOT NULL, order_date DATE DEFAULT SYSDATE NOT NULL, status VARCHAR2(10) DEFAULT 'NEW' NOT NULL, amount NUMBER(12,2) DEFAULT 0, remark VARCHAR2(500), CONSTRAINT pk_orders PRIMARY KEY (order_id) USING INDEX TABLESPACE demo_data, CONSTRAINT ck_orders_status CHECK (status IN ('NEW','PAID','SHIP','DONE','CANCEL')), CONSTRAINT ck_orders_amount CHECK (amount >= 0) ) TABLESPACE demo_data PARTITION BY RANGE (order_date) ( PARTITION p_2023 VALUES LESS THAN (DATE '2024-01-01'), PARTITION p_2024 VALUES LESS THAN (DATE '2025-01-01'), PARTITION p_max VALUES LESS THAN (MAXVALUE) );

几点值得注意。第一,主键用USING INDEX TABLESPACE显式指定索引表空间,不写就跟表走,在大表场景下数据和索引挤在一个表空间,备份和迁移都难受。第二,CHECK约束把状态机钉死在数据库层,比在应用层校验可靠——书里的示例喜欢这么写,实际项目也建议保留,代价是新增状态要改约束。第三,范围分区按时间切,是 11g 里最常见的分区方式;11g 还引入了间隔分区(INTERVAL子句),插入超出范围的数据会自动建分区,示例脚本里不常出现,但二次开发时很好用:

-- 间隔分区:按月自动扩展,不用手写 PARTITION 子句 CREATE TABLE logs ( log_id NUMBER, log_time DATE NOT NULL, content VARCHAR2(1000) ) PARTITION BY RANGE (log_time) INTERVAL (NUMTOYMINTERVAL(1,'MONTH')) (PARTITION p_init VALUES LESS THAN (DATE '2024-01-01'));

4.2 序列 + 触发器做主键自增的老路子

11g 没有IDENTITY列(那是 12c 才有的),书里的示例统一走“序列 + 触发器”这套组合:

CREATE SEQUENCE seq_orders_id START WITH 1000 INCREMENT BY 1 NOCACHE NOCYCLE; CREATE OR REPLACE TRIGGER trg_orders_id BEFORE INSERT ON orders FOR EACH ROW WHEN (NEW.order_id IS NULL) BEGIN SELECT seq_orders_id.NEXTVAL INTO :NEW.order_id FROM dual; END; /

WHEN (NEW.order_id IS NULL)这个条件很关键:有了它,你手工指定order_id插入不会被覆盖,脚本里预置的固定 ID 数据也不会被序列撞掉;没有它,所有 INSERT 都会被强制改号,造数脚本里那些写死的关联 ID 全乱。

NOCACHE是为了让序列号连续,代价是每次取号都写SEQ$数据字典,高并发下有争用。真实项目里我会改成CACHE 20,允许跳号换取性能——示例脚本为了演示“连续编号”保留 NOCACHE 可以理解,照搬到生产就得想清楚。

还有一个细节:SELECT ... INTO :NEW.col FROM dual必须带FROM dual。PL/SQL 里从序列取值不能直接:NEW.id := seq.NEXTVAL,这是语法限制,报PLS-00357。

4.3 存储过程与游标:一个批量结算的样本

书里综合案例一般会有一个“按月给客户结算”的过程,结构大致如下:

CREATE OR REPLACE PROCEDURE p_settle_month ( p_month IN VARCHAR2, -- 格式 YYYYMM p_count OUT NUMBER ) AS v_start DATE; v_end DATE; CURSOR c_orders IS SELECT cust_id, SUM(amount) total_amt FROM orders WHERE status = 'DONE' AND order_date >= v_start AND order_date < v_end GROUP BY cust_id; BEGIN v_start := TO_DATE(p_month || '01', 'YYYYMMDD'); v_end := ADD_MONTHS(v_start, 1); p_count := 0; FOR r IN c_orders LOOP MERGE INTO settle_stat t USING (SELECT r.cust_id cust_id FROM dual) s ON (t.cust_id = s.cust_id AND t.settle_month = p_month) WHEN MATCHED THEN UPDATE SET t.total_amt = t.total_amt + r.total_amt, t.update_time = SYSDATE WHEN NOT MATCHED THEN INSERT (cust_id, settle_month, total_amt, update_time) VALUES (r.cust_id, p_month, r.total_amt, SYSDATE); p_count := p_count + 1; END LOOP; COMMIT; EXCEPTION WHEN OTHERS THEN ROLLBACK; DBMS_OUTPUT.PUT_LINE('settle failed: ' || SQLERRM); RAISE; END p_settle_month; /

这段有几个可讲的地方。游标用了参数化的v_start/v_end,但它们是在BEGIN之后才赋值的——游标声明处引用变量,打开时才求值,所以顺序上没问题,这个写法在示例里很常见,也容易让人误以为要先赋值再声明。FOR r IN c_orders LOOP是显式游标的简化写法,自动 OPEN/FETCH/CLOSE,比手写LOOP ... EXIT WHEN c%NOTFOUND少一半代码。MERGE INTO做幂等写入,重跑同一个月不会翻倍,这是示例脚本里少见的“工程化”细节,值得抄。

4.4 异常处理与事务边界

上面那段结尾的EXCEPTION WHEN OTHERS THEN ROLLBACK; RAISE;,是示例代码里最该保留也最容易被删掉的三行。WHEN OTHERS捕获一切,SQLERRM拿到错误文本,RAISE把异常原样抛给调用方——三件事缺一不可:不ROLLBACK会留下半截数据;不打印SQLERRM调用方只看到一个ORA-06512栈;不RAISE则错误被吞掉,上层以为成功了。

更细致的写法是先命名异常再分支处理:

DECLARE e_dup EXCEPTION; PRAGMA EXCEPTION_INIT(e_dup, -00001); -- ORA-00001 唯一约束冲突 BEGIN INSERT INTO settle_stat(cust_id, settle_month, total_amt) VALUES (1001, '202401', 0); EXCEPTION WHEN e_dup THEN DBMS_OUTPUT.PUT_LINE('already settled, skip'); WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('unexpected: ' || SQLCODE || ' ' || SQLERRM); RAISE; END; /

PRAGMA EXCEPTION_INIT把错误号绑到自定义异常名上,好处是判断条件从SQLCODE = -1这种魔法数字变成有语义的名字。11g 里还有个DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,能打印出具体出错行号,比SQLERRM只有一行描述强得多,调试存储过程时我一直带着它。

事务边界要单独说一句:整个过程只在最后COMMIT一次。中间如果循环几万条,回滚段(UNDO 表空间)会被撑得很大,报ORA-01555: 快照过旧;工程上的折中是每 1000 条提交一次,代价是失败时不能整体回滚。示例代码为了讲清概念用单次提交,你二次开发时要按数据量重新算。

5. 避坑与排查:跑这份源程序最容易翻的几处

下面这几条不是从文档里抄的,是跑这类配套脚本时反复撞上的墙。每条按“现象 → 原因 → 解决”写,遇到同类问题可以直接对号入座。

第一条:脚本跑到一半卡住不动,光标一直闪。现象是执行到某个INSERT或者注释之后,SQL*Plus 停在那儿不返回,也没报错。 原因是脚本里出现了&符号,被当成了替换变量。Oracle 的示例数据里经常有 “R&D”、“A&B” 这种字符串,SET DEFINE默认是&,SQL*Plus 一见到就弹“输入 xxx 的值”,但在批量非交互模式下它就干等着。 解决是在脚本最前面统一加SET DEFINE OFF,注意要放在所有语句之前。另一个替代方案是SET DEFINE '~',把替换符换成一个罕见字符。这个坑的隐蔽之处在于:你如果只在图形工具里逐个文件跑,勾了“不提示替换变量”,永远遇不到,一上命令行批量执行就翻车。

第二条:中文全变问号,日志里一片???。现象是建表脚本里有中文注释,跑完之后查USER_TAB_COMMENTS,注释全是问号,数据里的中文也是问号。 原因有两个层面:客户端环境变量NLS_LANG没设或者设错;或者数据库字符集是ZHS16GBK,而脚本文件本身存的是 UTF-8。 解决顺序是先看数据库字符集:SELECT value FROM nls_database_parameters WHERE parameter='NLS_CHARACTERSET';,然后让客户端NLS_LANG与之一致;再确认脚本文件编码,UTF-8 的脚本喂给 GBK 库,光设环境变量不够,得先把文件转成 GBK 或者干脆重建库。这个错误不会报任何异常,纯靠肉眼发现,所以跑完一定要抽查几条含中文的数据。

第三条:ORA-00942: 表或视图不存在,但表明明建了。现象是 PL/SQL 脚本编译时报找不到某张表,去对象浏览器里一看,表好端端在那儿。 原因是大小写或者 schema 不对。Oracle 把不加双引号的标识符一律转大写,如果建表脚本里写了CREATE TABLE "orders"(带双引号的小写),那这张表的真名就是小写orders,而查询里写SELECT * FROM orders会被转成ORDERS,两者不匹配。 解决是统一规范:脚本里一律不加双引号,或者一律加双引号并统一大写。另一个可能是当前连接的用户不对,SELECT USER FROM dual确认一下,必要时用ALTER SESSION SET CURRENT_SCHEMA = demo;切过去,但切 schema 不等于有权限,还得确认SELECT授权。

第四条:存储过程状态INVALID,重跑也没用。现象是脚本执行完成,USER_OBJECTS里一堆INVALID,ALTER PROCEDURE ... COMPILE之后还是INVALID。 原因是依赖对象在编译那一刻还不存在,或者权限不足。比如过程引用了v$session,而用户只有CONNECT/RESOURCE,编译能过但执行报ORA-00942;反过来,如果过程引用了后创建的表,编译时表不存在就直接INVALID。 解决是先看SELECT * FROM USER_ERRORS WHERE NAME='P_XXX';,报错行号和文本写得很清楚;确认依赖表和权限都到位后,用DBMS_UTILITY.COMPILE_SCHEMA('DEMO', FALSE)按依赖关系重编译,比自己一个个ALTER靠谱。要注意COMPILE_SCHEMA第二个参数FALSE表示遇到错误继续,全量编译完再统一看。

**第五条:ORA-01653: 表空间 DEMO_DATA 无法通过 128 扩展。** 现象是造数脚本跑到某个大表时中断,报这个错。 原因是表空间数据文件到了MAXSIZE,或者磁盘满了。建表空间时如果写了MAXSIZE 4G,造几百万行示例数据很容易顶到上限。 解决分两步:先查SELECT tablespace_name, SUM(bytes)/1024/1024 mb FROM dba_data_files GROUP BY tablespace_name;确认还剩多少;再ALTER DATABASE DATAFILE '...' AUTOEXTEND ON NEXT 100M MAXSIZE 20G;放大上限,或者直接ALTER TABLESPACE demo_data ADD DATAFILE '...' SIZE 2G;加文件。根治办法是造数脚本里别用循环一行行插,改成INSERT ... SELECT FROM dual CONNECT BY LEVEL <= N` 批量生成,速度快几十倍,回滚段压力也小。

6. 二次开发:把示例脚本改成自己的库骨架

示例脚本跑通只是起点,真正省时间的是把它改造成自己的项目骨架。我的做法不是删了重写,而是在原结构上做三层替换。

第一层,替换命名空间。把demo用户、demo_data表空间、seq_orders_id这类前缀统一换掉,用 sed 批量替换比手工改安全:

# 先备份再替换,避免误伤 cp -r oracle11g_src oracle11g_src.bak grep -rl 'demo_data' oracle11g_src | xargs sed -i 's/demo_data/app_data/g' grep -rl 'DEMO_DATA' oracle11g_src | xargs sed -i 's/DEMO_DATA/APP_DATA/g'

注意大小写要分两轮替换,Oracle 的对象名在脚本里大小写混着写是常态,只替换一种必然漏。

第二层,按业务裁剪示例表。原包里的表往往是围绕一个教学案例设计的,关联关系比实际项目还复杂。我一般保留00_setup和目录结构,01_basic整段删掉,03_project里只留主表和核心过程,其余注释。裁剪后跑一遍USER_OBJECTS里INVALID为零,再往下走。

第三层,补上示例里没有的工程要素。原脚本基本不涉及这几样,但真项目必须有:

要素示例脚本里我补的方式
日志表无DBMS_OUTPUT改成写app_log表,带session_id和时间戳
幂等部分有 MERGE所有造数脚本加DELETE或MERGE前缀
参数化常量写死路径、schema 名抽到&1、&2或者单独的params.sql
版本标记无每张业务表加ver_no、create_time、update_time三列

最后一步验证,我不看脚本有没有报错,只看两件事:SELECT COUNT(*) FROM USER_OBJECTS WHERE STATUS='INVALID'是不是 0,以及把库整个 drop 掉重跑一遍run_all.sql能不能从零到有。第二件事听起来折腾,但它能一次性暴露所有“依赖当前环境里已有的对象”这种隐性毛病。从那以后我每次交付建库脚本,都强制在干净实例上从零跑一遍,跑不过就不算完成。希望这套拆法帮你把这份实例源程序用起来,而不是解压完放在硬盘里吃灰。

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