☰
Oracle 11.2.0.3补丁p20760997:OPatch应用与回滚避坑
2026/11/4 12:28:25 网站建设 项目流程

简介:面向Oracle数据库运维人员与DBA的11.2.0.3版本补丁集更新包,对应补丁编号20760997,适配Linux x86-64平台,内含2015年7月发布的关键补丁更新(CPU),主要用于修复该版本已披露的安全漏洞,并兼顾性能与稳定性改进,适合需要为生产库做季度安全加固、或对旧版本环境做集中维护的团队参考。压缩包整体约100.73MB,以补丁程序与配套说明文档为主,其中说明文件记录补丁的适用性、依赖关系与安装指引,补丁本体则承载实际应用到数据库实例上的修复内容,便于按官方流程完成校验与部署。已有293人学习下载。使用前建议结合官方文档确认前置补丁、备份策略与停机窗口;这份材料可用于梳理补丁集包含的修复条目、评估升级风险,并作为11.2.0.3环境安全加固与版本维护时的参考依据。

1. 一个 30MB 的 zip 里装了什么:从 p20760997 说开去

拿到p20760997_112030_Linux-x86-64.zip的人,多半是在某个变更窗口前一晚,被一句“把 oracle patch 打一下”推到了终端前面。它不是一个独立安装包,而是 11.2.0.3 在 Linux x86-64 平台上的一份补丁归档:解开后能看到编号20760997的目录、一份必须逐行读完的 README,以及若干待合并进$ORACLE_HOME的文件。它解决的问题很具体——把某个已知缺陷、某段安全修复、某处优化器行为变化补进现有库,而不需要重装数据库、不需要迁移数据。适用人群也很明确:手上有一批 11.2.0.3 单实例或 RAC、要在计划窗口内完成补丁合入并保留回滚路径的 DBA。这份东西的价值不在压缩包里,而在“顺序”——先做什么、后做什么、做错了怎么退。

2. 补丁坐标系:11.2.0.3 的 PSU、CPU 与 One-off 怎么分

动手之前先把坐标系建起来,否则很容易把一份 PSU 当成 one-off 打,或者在已经有多个 one-off 的库上直接 apply,然后卡在冲突检查那一步。补丁体系本身不复杂,复杂的是“这个补丁和我现有环境的关系”。

2.1 文件名拆解:p20760997_112030_Linux-x86-64 各段含义

这个命名是固定的几段拼起来的,读懂它比读 README 快。

段位取值含义容易误解的点
p固定前缀表示 patch不是 package
20760997八位数字补丁在补丁库里的编号它就是opatch rollback -id要用的 ID
112030版本串对应 11.2.0.3.0不是 11.2.0.30,也不是 11.2.0.3 的第三次修订
Linux-x86-64平台标识64 位 Linux平台不匹配时 apply 会直接拒绝

解开压缩包后的目录结构大同小异:顶层是补丁号目录,里面是README.html(或README.txt)、etc/config/inventory.xml、files/下的实际文件,有些补丁还会带custom/或postinstall脚本。判断一份包是不是“完整可打”,最省事的办法是看etc/config/inventory.xml是否存在且能被 OPatch 解析——缺这个文件,opatch apply会在读取阶段就报错,跟权限、空间都没关系。

unzip -l p20760997_112030_Linux-x86-64.zip | head -30

这条命令只看不写,用来确认压缩包内部第一层目录名是否与补丁号一致。参数上-l是列表模式,不会落盘;如果输出里出现多个顶层目录,说明这个包可能是套装(bundle),需要按 README 分别处理,不能整体当一份补丁 apply。

2.2 补丁类型与选型:什么时候打 PSU,什么时候只打 One-off

11.2.0.3 这个版本线上常见三类补丁,选错了轻则白干一个窗口,重则把 one-off 的修复覆盖掉。

第一类是 PSU(Patch Set Update),按季度发布、累积包含之前所有 PSU 的修复,同时内含当季的安全修复。它的特点是“越往后打越全”,适合作为生产库的常规节奏。第二类是 CPU(Critical Patch Update),只聚焦安全修复,体量小、影响面窄,适合安全合规有硬性要求但不想动优化器行为的场景。第三类是 One-off,针对单个缺陷,不累积、编号独立,通常来自某个 SR 的结论。

选型上我一般按这个顺序判断:如果 README 里明确写了“本补丁包含此前所有 PSU 修复”,且你的库当前只打过 PSU 没打过 one-off,直接按 PSU 处理;如果库里已经有若干 one-off,先lsinventory列出全部已装补丁,逐个比对 README 里的“superseded patches”列表,被新 PSU 覆盖的 one-off 必须先回滚再打,否则冲突检查过不去。还有一类容易被忽略:时区文件补丁(DST),它和 PSU 是两条线,README 里若要求同步更新时区版本,就得单独安排,不能指望 PSU 顺带解决。

提示:不要凭版本号猜补丁内容。同样叫 11.2.0.3 的库,装过的 PSU 月份不同,可打的下一份补丁也不同,唯一可靠的依据是opatch lsinventory -detail的输出加 README 的前置条件段落。

2.3 打补丁前必须读的 README 三件事

README 通常几十页,真正决定这次能不能打成功的是三处。

第一处是“Prerequisites”,包括 OPatch 的最低版本和必需的前置补丁号。前置补丁没打,opatch prereq会明确报缺哪个;OPatch 版本不够,apply 会以错误码 73 退出,且提示往往只有一行,很容易被当成别的问题。

第二处是“Installation Instructions”,核心是三个判断:要不要停库、打完要不要跑catbundle.sql、要不要额外执行脚本。11.2.0.3 的 PSU 基本都要跑catbundle.sql,这一步漏了会出现“二进制更新了、数据字典没更新”的半吊子状态。

第三处是“Known Issues”和“Rollback”,前者列出已知的、打完才暴露的问题及规避方式,后者给出回滚的确切步骤和顺序。很多回滚翻车是因为把opatch rollback和catbundle.sql psu rollback的执行顺序搞反了。

grep -n -A 20 -i "prerequisite" README.txt | head -40 grep -n -i "catbundle\|datapatch\|rollback" README.txt

这两条grep是在几百行文本里定位关键段落的快捷方式,-A 20表示命中行后再带出 20 行上下文,避免只看到标题看不到正文;第二条把“是否需要数据字典更新”和“回滚命令”一次性捞出来,比从头翻页快得多。

3. 动手前的三件硬活:OPatch 对齐、冲突预检与可回滚备份

补丁本身打起来只有一条命令,真正吃时间的是准备。准备阶段偷的懒,会在 apply 中途或打完验证时连本带利还回来,而且往往还伴着一次“要不要恢复备份”的艰难决策。

3.1 OPatch 版本对齐与 lsinventory 基线

OPatch 是独立于数据库版本演进的工具,11.2.0.3 的库配一个几年前下载的 OPatch,几乎必然在 apply 阶段失败。第一步永远是看版本。

# 查看当前 OPatch 版本 $ORACLE_HOME/OPatch/opatch version # 记录打补丁前的完整清单,作为回滚后的比对基线 mkdir -p /backup/p20760997 $ORACLE_HOME/OPatch/opatch lsinventory -detail -oh $ORACLE_HOME \ > /backup/p20760997/lsinventory_before.txt 2>&1

第一条输出形如OPatch Version: 11.2.0.3.x,拿这个号和 README 里的最低要求逐位比,差一个小版本都可能不兼容。第二条的-detail会列出每个已装补丁的 ID、描述和安装时间,-oh显式指定目标 ORACLE_HOME,避免在多实例机器上取错环境。这份文件不是走过场——回滚完成后拿它和新清单做 diff,能立刻看出有没有残留。

如果版本不够,正确做法是整体替换 OPatch 目录,不是把新文件往旧目录里拷。混合覆盖会造成部分脚本是新版、部分库文件是旧版,后续报错非常难查。

# 升级 OPatch 的标准动作:先挪走旧的,再放新的 mv $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch.bak.$(date +%Y%m%d) cp -rp /soft/opatch_new $ORACLE_HOME/OPatch chown -R oracle:oinstall $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch/opatch version

cp -rp的-p保留时间戳和权限,chown必须回到数据库软件属主,这两步少任何一步都可能在 apply 时抛出权限类错误。替换完再跑一次opatch version确认新版本生效,比在 apply 失败后回头排查省事得多。

3.2 冲突预检与前置补丁核对

OPatch 提供了专门的预检命令,它不写任何文件,只做判定,是窗口前最后一次“低成本失败”的机会。

cd /soft/psu/20760997 # 与目标 ORACLE_HOME 做冲突检查 $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./ # 检查补丁自身完整性 $ORACLE_HOME/OPatch/opatch prereq CheckPatchApply -ph ./

-ph ./指定当前目录为补丁目录,两个子检查的侧重点不同:前者判断这份补丁与已装补丁、已有文件是否冲突;后者判断补丁包结构、文件清单是否完整。输出里出现Failer或failed就不要往下走,先按提示处理冲突的 one-off。

冲突预检之外还要人工核对前置补丁。README 里列出的“Prerequisite Patches”必须已经在lsinventory里出现过,缺哪个先去补哪个——补丁之间是有依赖链的,跳过中间一环,即使 apply 侥幸成功,运行期也可能在某个包或视图上出问题。

3.3 备份策略:ORACLE_HOME、数据库与清单

回滚命令能解决大部分问题,但它解决不了“apply 中途磁盘写满导致文件损坏”这类情况,所以备份必须做,而且要做三层。

第一层是 ORACLE_HOME 的文件级备份,覆盖二进制和库文件:

# ORACLE_HOME 文件级备份,保留权限位 tar -pczf /backup/p20760997/oracle_home_before.tgz \ -C $ORACLE_HOME/.. $(basename $ORACLE_HOME)

-p保留权限,-C切到上级目录再打包,保证解包后路径结构一致;解包验证建议单独做一次tar -tzf列表检查,确认关键目录都在。11.2.0.3 的 ORACLE_HOME 通常几个 GB,压缩后体积可控,但前提是/backup分区有余量。

第二层是数据库备份。补丁本身不改业务数据,但catbundle.sql会动数据字典,执行异常时需要能回到打补丁前的状态。用 RMAN 做一次全备加归档备份,或者至少确保有一个可用的近期全备加完整归档链。

第三层是配置与清单备份:lsinventory输出、dba_registry快照、监听配置、参数文件。

sqlplus -s / as sysdba <<'EOF' set lines 200 pages 500 spool /backup/p20760997/registry_before.txt select * from registry$history order by action_time; select comp_name, version, status from dba_registry order by comp_name; spool off EOF

这段脚本在打补丁前抓取两样东西:registry$history记录每次数据字典变更,是判断catbundle.sql有没有真正执行过的直接证据;dba_registry列出各组件版本和状态,打完补丁后重新跑一遍对比,INVALID的组件就是后续要编译或排查的对象。spool落盘而不是只看屏幕,是因为变更窗口里滚屏信息很容易漏,事后复盘全靠这两个文件。

4. 打补丁全流程:从 unzip 到 catbundle.sql 的一杆到底

准备做完,正式操作其实是一条很短的链路:解压、停库、apply、起库、更新字典、验证。每一步的判定标准要提前想清楚,否则做到一半不确定“这算成功了吗”,只能凭感觉往下走。

4.1 解压与目录结构确认

mkdir -p /soft/psu cd /soft/psu unzip p20760997_112030_Linux-x86-64.zip cd 20760997 ls -l README.txt etc/config/inventory.xml

解压位置建议放在独立分区而不是/tmp,一是/tmp空间不确定,二是有些环境的/tmp挂了noexec,后续脚本执行会失败。确认README.txt和etc/config/inventory.xml同时存在,基本可以判定包是完整的。如果解压报“空间不足”,先df -h看目标分区,再决定换路径还是清空间——这个阶段失败没有任何损失,比 apply 到一半才发现要好得多。

4.2 停库与 opatch apply

单实例和 RAC 的停机范围不同,命令不能混用:

# 单实例:先停库,再停监听 sqlplus -s / as sysdba <<'EOF' shutdown immediate exit EOF $ORACLE_HOME/bin/lsnrctl stop # RAC 每个节点:停本节点集群服务 # crsctl stop crs -f

shutdown immediate会回滚未提交事务并做检查点,比abort安全;lsnrctl stop放在库停之后,避免停机过程中还有新连接进来。RAC 环境用crsctl stop crs -f停整个节点栈,注意这个命令要按节点逐个执行,且确认另一个节点能正常提供服务再动下一个,否则业务会在中间出现一段完全不可用的空档。

cd /soft/psu/20760997 $ORACLE_HOME/OPatch/opatch apply

执行过程中 OPatch 会先校验环境、再逐文件合并、最后写 inventory。看到OPatch succeeded.才算通过。中途失败会打印错误码,73 基本是 OPatch 版本问题,39 是补丁冲突,8 多是权限或环境变量问题。失败后不要急着反复重试,先看日志——OPatch 会在$ORACLE_HOME/cfgtoollogs/opatch/下留详细记录,比屏幕输出全得多。

批量环境可以用静默模式,避免交互确认卡住脚本:

$ORACLE_HOME/OPatch/opatch apply -silent

-silent只是跳过交互提问,判定逻辑不变,返回值仍需检查:echo $?为 0 才算成功。把它写进自动化脚本时,务必配合set -e或显式判断返回值,否则后面的步骤会在补丁没打上的情况下继续往下跑。

4.3 起库与 catbundle.sql 数据字典更新

二进制更新完只是第一步,数据字典还得跟上。

$ORACLE_HOME/bin/lsnrctl start sqlplus -s / as sysdba <<'EOF' startup @?/rdbms/admin/catbundle.sql psu apply exit EOF

catbundle.sql必须在实例处于 open 状态后执行,startup之后直接@调用,参数psu apply表示应用 PSU 对应的字典变更。执行过程会输出一串 DDL 和 PL/SQL 结果,要盯的是有没有ORA-开头的报错——尤其是ORA-04021(等待对象锁超时)和ORA-06512(存储过程异常),这两种往往意味着有会话没断干净或字典对象状态异常。

注意:11.2.0.3 走的是catbundle.sql,12c 以后才是datapatch。把 12c 的命令套到 11.2.0.3 上,会得到“脚本不存在”的错误,别在这个地方浪费窗口时间。

跑完之后建议再执行一次无效对象编译:

@?/rdbms/admin/utlrp.sql

utlrp.sql会重编译所有失效对象,执行时间与失效对象数量相关。它不能替代catbundle.sql,只是在字典变更后把依赖对象的状态拉回VALID,顺序不能颠倒。

4.4 验证:registry$history 与 lsinventory 双确认

验证要同时看“文件层”和“字典层”,只看一头容易误判。

select action, action_time, namespace, version, id, comments from registry$history order by action_time desc fetch first 10 rows only;

registry$history里应出现一条ACTION为APPLY、NAMESPACE为SERVER、VERSION与补丁对应的新记录。如果只看到旧的 PSU 记录,说明catbundle.sql没跑成功或没跑,需要回查执行输出。11.2.0.3 没有dba_registry_sqlpatch视图,不要照搬高版本的查询语句。

$ORACLE_HOME/OPatch/opatch lsinventory | grep -i 20760997 $ORACLE_HOME/OPatch/opatch lsinventory -detail -oh $ORACLE_HOME \ > /backup/p20760997/lsinventory_after.txt diff /backup/p20760997/lsinventory_before.txt /backup/p20760997/lsinventory_after.txt

第一条确认补丁 ID 已进清单;第二条留档;第三条 diff 出前后差异,正常情况下应该只多出这一份补丁相关条目,若出现意料之外的减少,说明有 one-off 被覆盖了,需要立刻确认是否符合预期。最后再把dba_registry跑一遍,组件状态全部VALID才算收工。

5. 避坑与回滚:五类翻车现场的现象、根因与处置

补丁流程本身不长,翻车点却很集中。下面五类是实际环境里反复出现的,按“现象、原因、解决”记下来,窗口里能省掉大量猜测时间。

5.1 OPatch 版本不足,apply 直接以 73 退出

现象:opatch apply刚开头就退出,提示OPatch failed with error code 73,日志里提到版本不满足要求。

原因:OPatch 是独立演进组件,旧版不认识新补丁的元数据格式;有些环境还叠加了JAVA_HOME指向错误 JDK 的问题,导致 OPatch 自身启动异常。

解决:按 3.1 的方式整体替换 OPatch 目录,替换后确认opatch version达标,并检查$ORACLE_HOME/OPatch/opatch脚本里的 Java 路径。不要试图修改补丁包去适配旧 OPatch,方向反了。

5.2 分区空间不足,apply 中途失败

现象:opatch apply执行到文件合并阶段报写入失败或磁盘满,退出后lsinventory里既没有新补丁,ORACLE_HOME下又可能留下半成品文件。

原因:apply 过程需要临时空间存放备份副本和合并中间文件,通常要求数倍于补丁体积;只看了补丁 zip 的大小,忽略了$ORACLE_HOME所在分区的余量。

解决:窗口前先df -h检查$ORACLE_HOME、/tmp、补丁解压目录三处空间。已经失败的情况下,不要直接重跑,先用opatch rollback -id(若 inventory 已写入)或从 3.3 的文件级备份恢复,再清掉残留目录后重来。

5.3 漏跑 catbundle.sql,出现二进制与字典不一致

现象:补丁打上了,lsinventory里有记录,但某些视图、包的编译时间还是旧的,业务侧报出与补丁修复项不符的行为,或者registry$history里查不到对应记录。

原因:opatch apply只更新文件系统,不改数据字典;catbundle.sql漏执行或执行中断,就会停在半更新状态。

解决:确认实例 open 后补跑@?/rdbms/admin/catbundle.sql psu apply,并检查输出里是否有ORA-报错;跑完再查registry$history和dba_registry,配合utlrp.sql编译失效对象。补跑前先确认补丁确实已 apply,否则会出现字典版本高于二进制的反向不一致。

5.4 已装 one-off 与新补丁冲突

现象:opatch prereq CheckConflictAgainstOHWithDetail报冲突,或 apply 阶段以 39 退出,日志点名某个已装 one-off 补丁号。

原因:新 PSU 已包含该 one-off 的修复,两者修改同一批文件,OPatch 不允许叠加。

解决:先opatch rollback -id <冲突补丁号>回滚 one-off,再 apply 新补丁;打完后核对 README 的 supersede 列表,确认被回滚的修复已由新补丁覆盖,不需要重打。回滚 one-off 前同样要做文件级备份,别只依赖 inventory。

5.5 RAC 只打了一个节点

现象:集群里部分节点补丁版本不一致,客户端连到未打节点时行为与已打节点不同,某些情况下还伴随 ORA-00600 类内部错误。

原因:opatch apply是节点级操作,不会自动传播;只在一台机器上执行,另一台仍是旧二进制。

解决:按节点逐个停集群服务、apply、起服务,顺序执行而不是并行;数据字典更新(catbundle.sql)在共享存储上只需执行一次,重复执行会报对象已存在类错误。全部节点完成后,在各节点分别跑opatch lsinventory | grep 20760997做交叉确认。

5.6 回滚路径:opatch rollback 与字典回退的顺序

回滚不是 apply 的逆操作那么简单,顺序错了会把状态搞得更乱。

# 1. 停库、停监听(RAC 停本节点集群服务) sqlplus -s / as sysdba <<'EOF' shutdown immediate exit EOF # 2. 文件层回滚 $ORACLE_HOME/OPatch/opatch rollback -id 20760997 # 3. 起库后回退字典变更 sqlplus -s / as sysdba <<'EOF' startup @?/rdbms/admin/catbundle.sql psu rollback exit EOF

-id后面跟的是补丁编号本身,不是文件名。catbundle.sql psu rollback依赖补丁留下的回滚脚本,因此必须在opatch rollback之后执行;顺序反了,脚本找不到对应目录会直接报错。回滚完成后同样用lsinventory与registry$history双向确认,并和 3.3 留下的基线文件做 diff。需要提醒的是,如果补丁应用后又执行过业务 DDL,字典回退只能回到补丁前的结构版本,业务变更本身不会被撤销,这部分要单独评估。

6. 收尾技巧:多节点顺序、静默参数与窗口校验清单

多节点环境最容易出问题的不是命令本身,而是节奏。我的习惯是先在备用节点上完整走一遍 apply 加 catbundle,确认无误后再动主节点,最后处理剩余节点;每动一个节点前,先确认其余节点能独立承载业务。静默模式配合响应文件可以让批量执行更稳,opatch apply -silent适合脚本调用,若环境需要指定参数,用-invPtrLoc指向正确的 inventory 指针文件,避免多套 ORACLE_HOME 并存时取错目标。

窗口结束前,我固定跑一遍下面这张清单,任何一项不通过就不算收工:

检查项命令或查询通过标准
文件层补丁opatch lsinventory | grep 20760997每个节点都能命中
字典层记录select * from registry$history order by action_time desc最新记录为本次 APPLY
组件状态select comp_name, status from dba_registry无 INVALID
失效对象select count(*) from dba_objects where status='INVALID'数量与打补丁前持平或为 0
监听与连接lsnrctl status加一次本地登录服务名正常、可登录
基线留档lsinventory_after.txt与registry_before.txt文件齐全可回溯

再补一个验证技巧:打完补丁后不要只看状态,抽一条补丁说明里提到的修复点做定向验证,比如某个视图的返回列、某个参数的可取值范围,确认行为确实变了。状态是VALID只说明对象能编译,不代表修复生效。

从那以后我每次开补丁窗口前,都会先把lsinventory和registry$history两份基线导出来,打完再 diff 一遍才敢关窗口——这个习惯救过我两次,一次发现 one-off 被意外覆盖,一次发现某个节点压根没执行成功。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询