简介:本资源是《Oracle 11g从入门到精通(第二版)》配套的完整实例源程序包,专为数据库初学者、SQL开发人员及备考OCP的DBA设计,聚焦“学以致用”,通过可运行代码深化对Oracle核心机制的理解与实操能力。压缩包共495个文件,涵盖236个SQL脚本(.txt)、123个编译类文件(.class)、44个Java源码(.java)、36个配置与元数据XML文件,以及JPG图示、备份脚本(.bak)、数据泵导出文件(.dmp)等,全面支撑19章内容的实验验证——从基础安装、表/索引创建,到存储过程、触发器、用户权限管理,再到RMAN备份恢复、分区优化与闪回技术。1.21MB轻量级包体便于快速下载与本地部署。目前已有404人学习下载,所有脚本均按章节结构组织,含大量注释与典型场景(如flashback_table、backup_tablespace、recover_database等),开箱即用,是系统掌握Oracle 11g管理与开发实践的关键辅助材料。
1. 这不是一本“翻完就扔”的Oracle书:它把11g的DDL、PL/SQL、备份恢复全塞进可运行的实例源程序里
你有没有试过学Oracle时,对着文档敲CREATE TABLE,结果报ORA-00922:missing or invalid option?或者写完一个存储过程,EXEC一执行就提示PLS-00306:wrong number of types of arguments?这不是你手生,是缺了“上下文”——缺一个真实数据库里跑得通的完整环境。这本《Oracle11g从入门到精通(第二版)》附带的.rar包,不是PDF里的截图代码,也不是脱库脱表的伪示例;它是一整套在Oracle 11.2.0.4实测通过的、带建库脚本+用户权限+数据插入+查询验证的可执行源程序集合。共137个.sql文件,覆盖第2章到第18章全部动手环节:从scott用户的emp/dept表初始化,到第15章RMAN全库备份脚本,再到第17章闪回查询的undo保留时间验证。适合刚装好Oracle 11g但卡在“连上去了却不知道下一步该建什么”的新手,也适合需要快速复现某类操作(比如物化视图刷新失败)的DBA。它不讲云原生或自治数据库,就死磕11g这个被大量政企系统锁定的稳定版本——因为现实里,你维护的很可能就是它。
2. 源程序结构解剖:137个.sql文件怎么组织?为什么必须按目录顺序执行?
这套源程序不是杂乱堆砌的SQL片段,而是按Oracle DBA日常运维和开发者的典型工作流分层组织的。我把它拆成四层逻辑结构,每层对应一类核心能力,且存在强依赖关系:下层未成功执行,上层必然报错。这种设计不是为了“显得专业”,而是还原真实生产环境中的约束链。
2.1 第一层:环境准备层(ch02_ch04/ 目录)
这是所有操作的地基,包含3类必需脚本:
create_user.sql:创建教学专用用户ora11g_test,并赋予CONNECT、RESOURCE、UNLIMITED TABLESPACE权限;create_tablespace.sql:建立ora11g_data和ora11g_idx两个表空间,分别存放数据和索引;init_scott.sql:完整重建scott用户及其emp/dept/salgrade三张表,并插入标准测试数据(56条emp记录,4条dept记录)。
提示:
init_scott.sql里有一处关键细节——它显式指定了emp表的hiredate字段使用TO_DATE('17-DEC-1980', 'DD-MON-YYYY')格式插入。这意味着你的数据库NLS_DATE_FORMAT必须兼容MON(英文缩写),否则会报ORA-01843:not a valid month。这不是bug,是刻意暴露本地化配置问题的设计。
2.2 第二层:对象构建层(ch05_ch09/ 目录)
这一层开始构建真实业务中高频使用的数据库对象。重点不是语法罗列,而是展示“为什么这样建”:
create_partition_table.sql:按sale_date范围分区的销售表,包含PARTITION p_2022 VALUES LESS THAN (TO_DATE('2023-01-01','YYYY-MM-DD'))。注意这里用的是TO_DATE而非字符串字面量,避免分区键类型隐式转换;create_materialized_view.sql:基于emp和dept的连接物化视图,刷新方式设为ON DEMAND,并附带BUILD IMMEDIATE。这意味着首次创建时就执行全量刷新,后续需手动调用DBMS_MVIEW.REFRESH;create_package.sql:一个名为pkg_emp_manage的包,含get_emp_count_by_dept函数和update_salary_by_dept过程。其规范写法是:包头(spec)只声明接口,包体(body)才实现逻辑,且UPDATE语句中明确使用WHERE CURRENT OF游标来更新当前行。
2.3 第三层:数据操作与事务层(ch10_ch13/ 目录)
这里直击Oracle事务控制的精髓。每个脚本都自带验证步骤,不是“执行完就结束”:
transaction_demo.sql:演示SAVEPOINT嵌套。先插入3条记录,设sp1;再插入2条,设sp2;然后ROLLBACK TO sp1。执行后查表,只剩最初3条——证明sp2之后的操作被清除,但sp1之前不受影响;bulk_collect_demo.sql:用BULK COLLECT INTO一次性取1000行emp数据到数组,再用FORALL批量更新。关键参数是LIMIT 500,防止内存溢出。若去掉此限,当emp表超2000行时,PL/SQL引擎可能抛出ORA-04030:out of process memory;flashback_query.sql:执行SELECT * FROM emp AS OF TIMESTAMP SYSTIMESTAMP - INTERVAL '5' MINUTE前,必须确保UNDO_RETENTION参数≥300(秒)。否则返回空集,不是没数据,是undo信息已被覆盖。
2.4 第四层:高可用与恢复层(ch14_ch18/ 目录)
这是DBA最怕出错的部分,源程序用最小可行脚本暴露关键路径:
rman_full_backup.sql:不是简单BACKUP DATABASE,而是带TAG 'FULL_BK_202405' FORMAT '/u01/backup/full_%U',并启用CONTROLFILE AUTOBACKUP ON。这意味着即使控制文件损坏,也能从自动备份中恢复;tablespace_point_in_time_recovery.sql:模拟users表空间误删后,用RECOVER TABLESPACE users UNTIL TIME '2024-05-20:10:00:00'恢复。注意:此操作要求数据库处于MOUNT状态,且必须先ALTER TABLESPACE users OFFLINE;data_pump_export_import.sql:导出ora11g_test用户下所有对象,用expdp命令行调用,但脚本里预置了PARFILE=expdp.par内容——其中EXCLUDE=STATISTICS是血泪经验:避免导入时因统计信息版本不匹配导致执行计划异常。
3. 执行前必做的5项环境校验:别让ORA错误毁掉第一印象
很多开发者解压后直接双击ch02/create_user.sql,结果满屏红色ORA错误,以为书有问题。其实90%的情况,是环境没对齐。以下5项检查必须在SQL*Plus或SQL Developer中逐条确认,缺一不可:
3.1 数据库版本与字符集校验
-- 在SQL*Plus中执行 SELECT * FROM v$version WHERE banner LIKE 'Oracle%'; SELECT parameter, value FROM nls_database_parameters WHERE parameter IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');预期输出:banner含Oracle Database 11g Enterprise Edition Release 11.2.0.4.0;NLS_CHARACTERSET应为AL32UTF8或ZHS16GBK(中文Windows常见)。若为WE8ISO8859P1等西欧字符集,执行含中文注释的.sql文件会报ORA-01756:quoted string not properly terminated——因为单引号被当成了字符串边界而非注释符号。
3.2 默认表空间与临时表空间检查
-- 查看当前用户默认表空间 SELECT username, default_tablespace, temporary_tablespace FROM dba_users WHERE username = 'SYS'; -- 查看表空间状态 SELECT tablespace_name, status, contents FROM dba_tablespaces;关键点:default_tablespace不能是SYSTEM或SYSAUX(违反最佳实践),且目标表空间(如ora11g_data)状态必须为ONLINE。若为READ ONLY,执行CREATE TABLE会报ORA-01653:unable to extend table。
3.3 归档模式与闪回开关状态
-- 必须开启归档,否则RMAN备份脚本失败 ARCHIVE LOG LIST; -- 闪回数据库需开启(ch17相关脚本依赖) SELECT flashback_on FROM v$database;若ARCHIVE LOG LIST显示No Archive Mode,需重启数据库至MOUNT状态后执行ALTER DATABASE ARCHIVELOG;若flashback_on为NO,则FLASHBACK DATABASE TO TIMESTAMP类操作直接报错,无法跳过。
3.4 权限与资源限制检查
-- 确认当前用户有CREATE SESSION权限(登录基础) SELECT * FROM session_privs WHERE privilege = 'CREATE SESSION'; -- 检查profile资源限制(防INSERT卡住) SELECT resource_name, limit FROM dba_profiles WHERE profile = (SELECT profile FROM dba_users WHERE username = 'SYS') AND resource_name IN ('FAILED_LOGIN_ATTEMPTS', 'PASSWORD_LOCK_TIME');常见陷阱:FAILED_LOGIN_ATTEMPTS设为3且PASSWORD_LOCK_TIME为UNLIMITED,会导致多次密码输错后账户永久锁定。源程序中create_user.sql虽建了新用户,但若DEFAULT PROFILE太严,新用户也会继承。
3.5 客户端NLS_LANG环境变量设置
这不是数据库端配置,而是你运行SQL*Plus的机器上的环境变量。Windows下在命令行执行:
# Windows PowerShell $env:NLS_LANG="AMERICAN_AMERICA.AL32UTF8" # 或中文环境 $env:NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"Linux/macOS下在shell中:
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8 # 必须在启动sqlplus前设置,否则日期/数字格式解析错乱现象:不设NLS_LANG时,TO_DATE('2024-05-20', 'YYYY-MM-DD')可能被解析成0020-05-00(年份错位),因为客户端用本地locale解释字符串。
4. 避坑指南:执行源程序时最常踩的7个深坑及自救方案
这些不是理论错误,是我在线上环境帮某高校实验室部署教学库时,连续3天反复遇到的真实翻车现场。每一条都对应一个具体.sql文件的执行失败,且解决方案已验证有效。
4.1 现象:ch05/create_partition_table.sql执行时报ORA-14036:partition bound value too large
原因:分区键字段sale_date DATE的值超出了Oracle DATE类型支持范围(公元前4712年1月1日到公元9999年12月31日)。源程序中某条INSERT用了TO_DATE('9999-12-31', 'YYYY-MM-DD'),看似合法,但某些补丁版本的11.2.0.4会对此做额外校验。
解决:打开create_partition_table.sql,将所有VALUES LESS THAN (TO_DATE('9999-12-31',...))改为VALUES LESS THAN (MAXVALUE)。MAXVALUE是Oracle专为分区设计的无穷大占位符,无版本兼容性问题。
4.2 现象:ch12/bulk_collect_demo.sql执行到FORALL i IN 1..emp_list.COUNT UPDATE emp SET sal = sal * 1.1 WHERE empno = emp_list(i).empno;时卡住10分钟,最后报ORA-00060:deadlock detected
原因:脚本中emp_list数组包含重复empno,导致FORALL尝试对同一行并发更新。Oracle检测到行级锁冲突,触发死锁检测机制。
解决:在BULK COLLECT后添加去重逻辑:
-- 在DECLARE段后加 TYPE empno_tab IS TABLE OF emp.empno%TYPE; v_unique_empnos empno_tab; ... -- 在BULK COLLECT后加 SELECT DISTINCT empno BULK COLLECT INTO v_unique_empnos FROM TABLE(emp_list); -- 然后用v_unique_empnos替代emp_list执行FORALL4.3 现象:ch14/rman_full_backup.sql中BACKUP DATABASE PLUS ARCHIVELOG DELETE INPUT执行后,V$ARCHIVED_LOG里仍有归档日志未删除
原因:DELETE INPUT只删除已备份的归档,但若存在ARCHIVELOG ALL命令未完成的归档(如正在写入的当前日志),RMAN会跳过它们。源程序未检查V$ARCHIVED_LOG.DELETED = 'NO' AND STANDBY_DEST = 'NO'的残留日志。
解决:备份后手动清理:
-- 先查残留 SELECT name, first_time, deleted FROM v$archived_log WHERE deleted = 'NO' AND standby_dest = 'NO' ORDER BY first_time; -- 再删除(需在MOUNT状态) SHUTDOWN IMMEDIATE; STARTUP MOUNT; DELETE NOPROMPT ARCHIVELOG ALL COMPLETED BEFORE 'SYSDATE-1';4.4 现象:ch16/data_pump_export_import.sql中impdp导入时报ORA-39083:Object type TABLE:"ORA11G_TEST"."EMP" failed to create
原因:源程序导出时未排除CONSTRAINT,而目标库中emp表已存在(因前面init_scott.sql已建),impdp默认行为是跳过已存在对象,但约束名冲突导致失败。
解决:修改impdp命令,强制替换:
impdp ora11g_test/password DIRECTORY=dp_dir DUMPFILE=expdp.dmp TABLE_EXISTS_ACTION=REPLACE EXCLUDE=STATISTICSTABLE_EXISTS_ACTION=REPLACE是关键,它会先DROP再CREATE表及其约束。
4.5 现象:ch17/flashback_query.sql中AS OF TIMESTAMP查询返回空集,但V$UNDOSTAT显示UNDOBLKS有值
原因:UNDO_RETENTION参数设为1800(30分钟),但实际undo表空间UNDOTBS1的RETENTION GUARANTEE未开启,Oracle在空间压力下仍会覆盖旧undo。
解决:开启保证模式:
-- 需SYS用户执行 ALTER TABLESPACE undotbs1 RETENTION GUARANTEE; -- 并增大undo表空间(若空间不足) ALTER DATABASE DATAFILE '/u01/oradata/undotbs01.dbf' RESIZE 2G;4.6 现象:ch08/create_package.sql编译包体时报PLS-00201:identifier 'PKG_EMP_MANAGE.GET_EMP_COUNT_BY_DEPT' must be declared
原因:包头(spec)和包体(body)未在同一用户下创建,或包头编译失败但未报错(因SQL*Plus默认WHENEVER SQLERROR CONTINUE)。
解决:严格按顺序执行,且每步后检查:
-- 先编译包头 @ch08/create_package_spec.sql SHOW ERRORS PACKAGE pkg_emp_manage; -- 再编译包体 @ch08/create_package_body.sql SHOW ERRORS PACKAGE BODY pkg_emp_manage;SHOW ERRORS会列出所有PL/SQL编译错误,比单纯看PL/SQL procedure successfully completed可靠得多。
4.7 现象:ch03/init_scott.sql执行后,SELECT * FROM emp显示HIREDATE列为NULL,但脚本里明明写了TO_DATE
原因:数据库NLS_DATE_FORMAT为DD-MON-RR,而脚本中TO_DATE('17-DEC-1980', 'DD-MON-YYYY')的YYYY与RR不匹配,导致转换失败返回NULL。
解决:临时修改会话级格式:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY'; -- 再执行init_scott.sql @ch03/init_scott.sql或更彻底:在init_scott.sql开头加ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY';。
5. 验证执行结果的4种硬核方法:别信“执行成功”,要看数据在不在
源程序执行完,屏幕上飘过一串PL/SQL procedure successfully completed,你就信了?线上事故往往就栽在这种“看起来没问题”的假象里。我总结了4种必须落地的验证手段,每一种都对应一个可复制的命令或查询,不依赖GUI工具,纯SQL*Plus就能跑。
5.1 表结构一致性验证:用DBMS_METADATA.GET_DDL比对
源程序声称创建了分区表sales_part,但你怎么确认它真是按RANGE分区、且有p_2022和p_2023两个分区?不能只查USER_TABLES,要挖到底层定义:
-- 获取sales_part表的完整DDL SELECT DBMS_METADATA.GET_DDL('TABLE', 'SALES_PART', 'ORA11G_TEST') FROM DUAL; -- 关键验证点: -- 1. 输出中必须含 "PARTITION BY RANGE (sale_date)" -- 2. 必须含 "PARTITION p_2022 VALUES LESS THAN (TO_DATE('2023-01-01','YYYY-MM-DD'))" -- 3. 分区数应等于预期(此处为2) -- 若输出为空,说明表不存在;若不含PARTITION BY,则创建失败注意:
DBMS_METADATA.GET_DDL返回的是CLOB,SQL*Plus默认只显示前80字符。需先执行SET LONG 10000,否则你看不到完整DDL。
5.2 数据完整性验证:用DBMS_STATS.GATHER_TABLE_STATS反向推断
源程序在ch03/init_scott.sql中插入了56条emp记录,但若中途INSERT被ROLLBACK或COMMIT遗漏,数据就丢了。与其数行,不如让Oracle自己告诉你:
-- 收集统计信息(强制刷新) EXEC DBMS_STATS.GATHER_TABLE_STATS('ORA11G_TEST', 'EMP', CASCADE => TRUE); -- 查询统计信息视图 SELECT table_name, num_rows, blocks, last_analyzed FROM user_tables WHERE table_name = 'EMP'; -- 预期:NUM_ROWS = 56,LAST_ANALYZED为当前时间 -- 若NUM_ROWS = 0,说明表空;若为NULL,说明统计信息未收集(即表可能未创建)这个方法的妙处在于:GATHER_TABLE_STATS会扫描物理数据块,NUM_ROWS是真实行数,不是COUNT(*)的逻辑计数(后者可能被事务隔离级别干扰)。
5.3 逻辑功能验证:用DBMS_OUTPUT.PUT_LINE捕获PL/SQL执行痕迹
ch12/bulk_collect_demo.sql说它批量更新了工资,但更新了多少行?是否真用了FORALL?光看SQL> 56 rows updated.不够,要看到PL/SQL引擎内部动作:
-- 修改原脚本,在FORALL后加 DBMS_OUTPUT.PUT_LINE('FORALL processed ' || SQL%ROWCOUNT || ' rows'); -- 并在SQL*Plus中开启输出 SET SERVEROUTPUT ON -- 再执行 @ch12/bulk_collect_demo.sql -- 预期输出末尾有: -- FORALL processed 56 rows -- 若输出为0,说明FORALL未执行(可能因数组为空或条件不满足)SQL%ROWCOUNT是PL/SQL内置属性,返回上一条DML语句影响的行数,比SELECT COUNT(*)更直接反映执行效果。
5.4 备份有效性验证:用LIST BACKUP和RESTORE VALIDATE
ch14/rman_full_backup.sql生成了备份集,但备份文件存在≠备份可用。必须验证RMAN能识别且能恢复:
# 在RMAN中执行 RMAN> CONNECT TARGET / RMAN> LIST BACKUP OF DATABASE SUMMARY; # 查看输出中是否有STATUS = 'AVAILABLE'的备份集 RMAN> RESTORE DATABASE VALIDATE; # 此命令不真恢复,只校验备份集能否读取、控制文件能否定位 # 成功时输出:"channel ORA_DISK_1: validation complete" # 失败时会明确指出哪个备份片损坏或缺失这是DBA上线前必做的一步。我见过太多案例:备份脚本每天跑,日志显示成功,但某次磁盘坏道导致备份片静默损坏,直到真要恢复时才发现——而VALIDATE能在5分钟内暴露问题。
6. 进阶技巧:把137个.sql文件变成可调试的模块化开发环境
源程序的价值不止于“照着执行”,它是一套可拆解、可组合、可调试的Oracle技能训练框架。我把137个文件重新组织成4个可独立加载的模块,每个模块配一个主入口脚本,支持参数化执行、失败自动回滚、执行日志归档。这不是书里教的,是我给某公司DBA团队做的内部培训方案,已稳定运行2年。
6.1 模块化设计原则:解耦、可逆、可观测
传统做法是@ch02/create_user.sql→@ch03/init_scott.sql…一路敲下去,一旦中间出错,就得手动清理。我的模块化方案强制三点:
- 解耦:每个模块只依赖上层模块的输出(如“对象构建模块”依赖“环境准备模块”创建的用户和表空间),不依赖其他模块的具体SQL;
- 可逆:每个模块自带
rollback_*.sql脚本,执行@module_x/rollback.sql即可清理该模块所有变更; - 可观测:每个主脚本执行前自动生成唯一
RUN_ID,所有日志、错误、执行时间写入module_log表,便于审计。
6.2 四大模块结构与主入口脚本
| 模块名称 | 目录路径 | 主入口脚本 | 核心能力 | 关键参数 |
|---|---|---|---|---|
| CoreEnv | /modules/core_env/ | run_core_env.sql | 创建用户、表空间、初始化scott | &1:用户名(默认ora11g_test);&2:表空间名(默认ora11g_data) |
| SchemaObj | /modules/schema_obj/ | run_schema_obj.sql | 创建表、索引、视图、物化视图 | &1:是否启用分区(Y/N);&2:物化视图刷新方式(ON DEMAND/ON COMMIT) |
| DataProc | /modules/data_proc/ | run_data_proc.sql | 批量DML、PL/SQL包、闪回查询 | &1:批量大小(默认500);&2:闪回时间偏移(默认5分钟) |
| Recovery | /modules/recovery/ | run_recovery.sql | RMAN备份、数据泵导入、表空间PITR | &1:备份路径(默认/u01/backup);&2:PITR时间点(默认SYSDATE-1) |
提示:所有
&1、&2参数在SQL*Plus中用DEFINE传入,例如:DEFINE 1 = 'myuser',DEFINE 2 = 'myts',避免硬编码。
6.3 主入口脚本示例:run_schema_obj.sql的健壮性设计
这个脚本不是简单串联多个@,它实现了真正的工程化控制流:
-- run_schema_obj.sql SET VERIFY OFF SPOOL /u01/logs/schema_obj_&1._&2..log -- 步骤1:记录开始时间与参数 VARIABLE run_id VARCHAR2(50) EXEC :run_id := 'SCHEMA_' || TO_CHAR(SYSDATE, 'YYYYMMDD_HH24MISS') || '_' || '&1'; INSERT INTO module_log (run_id, module, start_time, params) VALUES (:run_id, 'SCHEMAOBJ', SYSDATE, '&1.&2'); COMMIT; -- 步骤2:按依赖顺序执行,每步检查SQLCODE BEGIN @/modules/schema_obj/create_table.sql; IF SQLCODE != 0 THEN RAISE_APPLICATION_ERROR(-20001, 'create_table failed'); END IF; @/modules/schema_obj/create_index.sql; IF SQLCODE != 0 THEN RAISE_APPLICATION_ERROR(-20002, 'create_index failed'); END IF; -- 动态选择是否执行分区脚本 IF '&1' = 'Y' THEN @/modules/schema_obj/create_partition_table.sql; END IF; END; / -- 步骤3:验证并记录结果 DECLARE v_count NUMBER; BEGIN SELECT COUNT(*) INTO v_count FROM user_tables WHERE table_name = 'EMP'; INSERT INTO module_log (run_id, module, end_time, status, details) VALUES (:run_id, 'SCHEMAOBJ', SYSDATE, 'SUCCESS', 'EMP table exists: ' || v_count); COMMIT; EXCEPTION WHEN OTHERS THEN INSERT INTO module_log (run_id, module, end_time, status, details) VALUES (:run_id, 'SCHEMAOBJ', SYSDATE, 'FAILED', SQLERRM); COMMIT; RAISE; END; / SPOOL OFF这段脚本的关键在于:
SPOOL将所有输出重定向到带时间戳的日志文件,方便事后排查;RAISE_APPLICATION_ERROR在每步后主动检查,避免错误被忽略;IF '&1' = 'Y'实现参数化分支,不用改代码就能切功能;module_log表是自建的审计表,结构简单:RUN_ID VARCHAR2(50), MODULE VARCHAR2(20), START_TIME DATE, END_TIME DATE, STATUS VARCHAR2(10), DETAILS VARCHAR2(4000)。
6.4 故障注入测试:故意制造失败,验证模块可逆性
模块化最大的价值是敢“破坏”。我常做的一件事是:在run_schema_obj.sql执行到一半时,手动KILL会话,然后运行rollback_schema_obj.sql:
-- rollback_schema_obj.sql -- 1. 删除所有表(按依赖倒序) DROP TABLE sales_part CASCADE CONSTRAINTS; DROP TABLE emp CASCADE CONSTRAINTS; -- 2. 删除所有索引 DROP INDEX idx_emp_deptno; -- 3. 删除物化视图 DROP MATERIALIZED VIEW mv_emp_dept; -- 4. 清理日志表记录 DELETE FROM module_log WHERE module = 'SCHEMAOBJ' AND run_id LIKE 'SCHEMA_%'; COMMIT;执行后,SELECT * FROM user_tables应为空。如果还有残留,说明CASCADE CONSTRAINTS没起作用,或是外键跨用户——这就暴露了源程序中CREATE TABLE未显式指定CONSTRAINT名称的隐患(Oracle会自动生成SYS_C00xxxx名,DROP时难定位)。
从那以后我每次搭建新环境,都强制走一遍run_xxx.sql+rollback_xxx.sql的闭环。不是为了炫技,是因为Oracle的DDL不像应用代码能轻易回滚,一次DROP TABLE手抖,可能就得从备份恢复。希望帮到你。
本文还有配套的精品资源,点击获取