必须用SELECT text FROM ALL_SOURCE或DBA_SOURCE WHERE owner='SCHEMA' AND name='PROC_NAME' ORDER BY line导出,加ORDER BY line确保代码顺序正确,避免语法错误;生产库优先用ALL_SOURCE防权限不足,开发库可用DBA_SOURCE。
oracle 存储过程本身不存版本历史,create or replace procedure 一执行就覆盖原内容,想靠数据库自己记住“上一版”不可能——必须用外部脚本把源码捞出来、打标签、存 git。
怎么从数据库导出存储过程源码?
核心是查 DBA_SOURCE 或 ALL_SOURCE,按行号排序拼回完整代码。别直接用 SELECT text FROM DBA_SOURCE WHERE name = 'MY_PROC' 就完事,容易乱序或漏行。
- 必须加
ORDER BY line,否则导出的代码可能语法错误 - 生产库建议用
ALL_SOURCE(避免没SELECT ANY DICTIONARY权限报错),开发库可用DBA_SOURCE - 导出时过滤掉空行和注释行(可选),但别删掉
CREATE OR REPLACE开头——这是重载必需的 - 命令示例:
sqlplus -s /nolog <<EOF CONNECT $USER/$PASS@$SID SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SPOOL my_proc_v1.3.sql SELECT text FROM ALL_SOURCE WHERE owner = 'MY_SCHEMA' AND name = 'MY_PROC' ORDER BY line; SPOOL OFF EXIT EOF
为什么不能只靠数据库触发器记 DDL?
有人建 A_Ver_Control 表 + AFTER DDL ON SCHEMA 触发器来抓 CREATE OR REPLACE,但这只能记录“谁什么时候改了”,不能还原可执行的源码。
- 触发器里用
DBMS_METADATA.GET_DDL取出的 DDL 带有系统生成的依赖信息(比如表空间名、存储参数),和你手写的源码不一致 - 它不保存注释、空格、格式——而这些对理解逻辑很关键
- 如果过程里调用了其他未授权对象,
GET_DDL可能返回ORA-31603错误,导致记录失败 - 真正要回滚,你得拿 Git 里那个带注释、可 review 的
.sql文件重新执行,不是靠触发器里的 CLOB
Shell 脚本怎么自动化拉取+提交?
一个最小可行脚本要完成三件事:连接数据库导出、生成带时间戳的文件名、推到 Git。别写成单个超长命令,拆成函数更易维护。
- 导出文件名建议含版本号和时间,比如
my_proc_$(date +%Y%m%d_%H%M)_v1.4.sql - 每次提交前先
git pull --rebase,避免合并冲突(尤其多人协作时) - Git 提交信息固定格式,例如:
[PROC] MY_PROC updated by $USER on $(date),方便后期git log --grep查 - 关键检查点:导出后
grep -q "CREATE OR REPLACE PROCEDURE" my_proc_*.sql,失败则退出脚本,不提交残缺文件 - 示例片段:
export_file="my_proc_$(date +%Y%m%d_%H%M)_v1.4.sql" sqlplus -s $CONN_STR @export_proc.sql $export_file || { echo "Export failed"; exit 1; } git pull --rebase || { echo "Git pull failed"; exit 1; } git add "$export_file" && git commit -m "[PROC] MY_PROC updated by $USER on $(date)" && git push
哪些地方最容易被忽略?
不是导出成功就算完事。真正的坑在权限、编码、上下文三处:
-
DBA_SOURCE需要SELECT ANY DICTIONARY,普通用户常只有ALL_SOURCE,查不到别人 Schema 下的过程——脚本里得提前校验SELECT COUNT(*) FROM ALL_SOURCE WHERE ...是否 > 0 - 导出文件默认是数据库字符集(如 AL32UTF8),但 Git 默认按 UTF-8 处理;如果数据库用 ZHS16GBK,脚本里得加
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK,否则中文注释变乱码 - 过程里如果有
$$PLSQL_UNIT或$$PLSQL_LINE这类编译器常量,它们在导出后失去意义,但不会报错——人工 review 时得留意是否误用了调试专用逻辑


















