资讯动态

Oracle 11.2.0.3补丁实战:OPatch应用、PSU后处理与回滚

发布时间:2026/10/27 11:02:59 来源:尧图企业网站定制
简介这是一份面向Oracle数据库运维人员与DBA的补丁归档包对应补丁编号20760997适用于Linux x86-64平台上的Oracle 11.2.0.3版本属于11.2.0.3.15数据库补丁集更新并包含2015年7月发布的CPU关键补丁更新。对需要复核旧版本修复内容、补齐安全补丁或做版本维护记录的技术人员而言它提供了可留存、可查阅的补丁材料。压缩包整体约100.73MB文件总数显示为0、主要文件类型明细暂无数据具体包内结构需以下载后的实际内容为准结合描述可知其中包含补丁搜索配置信息与实际补丁程序便于核对适用性、依赖关系和版本边界。该资源已有291人浏览学习在Oracle补丁整理与旧系统维护场景中具有一定参考需求。其价值在于将特定小版本的安全修复与稳定性更新集中归档读者可据此了解该补丁集覆盖的CPU内容、适用平台及版本范围为补丁比对、安全整改和日常维护记录提供依据适合作为DBA补丁管理工作的参考资料。1. 凌晨的补丁包p20760997_112030_Linux-x86-64.zip 到底该不该动凌晨一点半一套跑着 11.2.0.3 的单实例库要做季度补丁窗口群里发过来一个包p20760997_112030_Linux-x86-64.zip。多数人第一反应是解压、opatch apply、重启然后等结果。这串文件名不是乱码而是 oracle patch 的标准命名p后面是补丁号112030是目标库的版本位11.2.0.3.0Linux-x86-64是平台位。三个字段里读错任何一个轻则opatch在预检阶段就会报错重则把一批不匹配的二进制文件放进 ORACLE_HOME事后再想回滚只能依赖备份。这篇围绕这个 zip 讲三件事文件名怎么解码、在 Linux x86-64 上从解压到验证的完整命令序列、以及我实际踩过的五个问题。适合手里正拿着一个补丁包不敢下手的初级 DBA也适合想把自己的打补丁流程做成可复用台账的熟手。2. 拆开文件名三个字段决定这份补丁能不能实施2.1 补丁号、版本位、平台位读错一位就白干Oracle 的补丁包命名是固定格式p补丁号_版本位_平台位.zip。补丁号是下载时挂在补丁说明上的编号也是后面opatch rollback -id、.patch_storage目录定位、lsinventory里比对用的键。版本位是五位数字112030对应 11.2.0.3.0前两位是主版本后面依次是次版本、末位、以及补丁集内的第五位。平台位直接对应uname -m的输出和 inventory 里登记的平台标识。补丁包里有一份etc/config/inventory.xml里面写着target_version。opatch apply做的第一件事就是拿这个值和目标 ORACLE_HOME 在 inventory 里登记的版本比对不一致就中止。所以“我这个库是 11.2.0.4能不能顺手打 11.2.0.3 的包”这类问题答案是不能也不是“改一下文件名就行”。片段本例取值含义读错后的典型后果p2076099720760997补丁号回滚与存储定位的键rollback -id找不到备份目录11203011.2.0.3.0目标版本位报Patch is not applicable to this Oracle HomeLinux-x86-64x86_64平台位同上或 opatch 无法识别平台还有一个文件名看不出来的维度补丁类型。11.2.0.3 上的补丁大致分两类累积型的 PSU 和单点型的 one-off/interim。PSU 需要在二进制打完之后额外执行catbundle.sql把数据库字典侧的变更刷进去one-off 通常只需要重编译无效对象。区分方法只有一条打开解压出来的README.html看它有没有“Load PSU”或“catbundle”相关段落。这一步花两分钟能省掉后面两小时的排查。2.2 OPatch 是前置依赖版本不够后面全免谈opatch不是系统自带工具它是 ORACLE_HOME 里的一个独立目录跟着补丁一起迭代。新补丁会用到新的元数据解析逻辑所以补丁说明里通常有一节写死最低 OPatch 版本要求。当前版本低于要求时opatch apply会在解析补丁元数据阶段直接退出日志里出现版本检查失败的提示连冲突检查都跑不到。查版本很简单export ORACLE_HOME/u01/app/oracle/product/11.2.0/dbhome_1 $ORACLE_HOME/OPatch/opatch version # 或者看脚本本身指向的 java head -30 $ORACLE_HOME/OPatch/opatch | grep -i java升级 OPatch 的正确做法是替换整个目录不要往里覆盖文件。先停掉所有使用这个 home 的进程把旧目录改名备份再把新版本解压到$ORACLE_HOME下递归改属主然后用两条命令交叉验证opatch version确认版本号变了opatch lsinventory确认新工具能正常读出旧 inventory。第二条尤其关键很多人只看了版本号就往下走结果lsinventory一跑就报找不到 inventory。注意一个 ORACLE_HOME 的 OPatch 不要跨大版本混用11.2 的 home 里放入更高大版本的 OPatch常见结果是lsinventory能跑、apply报奇怪的解析错误排查方向会被带偏。多 home 的机器上还有一个隐藏坑opatch默认从/etc/oraInst.loc或$ORACLE_HOME/oraInst.loc找中央 inventory。两个文件指向不一致时opatch读到的可能是另一个 home 的登记信息。遇到Unable to find the inventory或补丁明明匹配却报 not applicable用-invPtrLoc显式指定指针文件问题基本就定位了。2.3 四项前置检查冲突、空间、权限、实例状态正式打之前值得花十分钟跑四项只读检查。它们不改任何东西失败了也不会有副作用但能挡掉后面八成的翻车。第一项是冲突检查。opatch prereq CheckConflictAgainstOHWithDetail -ph /u01/patch/20760997会把补丁和当前 home 已安装补丁的文件级冲突列出来。看到冲突不要条件反射地加跳过参数先回到 README 看这个补丁是否已被更高版本包含、被冲突补丁取代。冲突检查通过后输出里的SUMMARY段是Passed才算干净。第二项是空间。补丁在替换文件前会把原始文件备份到$ORACLE_HOME/.patch_storage所以实际占用往往远大于补丁包本身。经验值是按 ORACLE_HOME 体积的 1.5 倍预留同时留意/tmp是否和 ORACLE_HOME 在同一个文件系统上——日志和临时文件把它吃满apply会中途失败。第三项是权限。ls -ld $ORACLE_HOME看清 owner 是谁id确认自己是不是那个用户。用 root 跑opatch是新手高频错误它会先把文件复制成 root 属主然后报复制失败或者留下一个属主错乱的 home后续启动实例直接起不来。第四项是实例状态。数据库、监听、ASM、以及任何链接了$ORACLE_HOME/lib/libclntsh.so的第三方进程都要停。opatch prereq CheckActiveFilesAndExecutables -ph /u01/patch/20760997能直接告诉你还有哪些可执行文件和库被占用。RAC 环境下别忘了另一台节点的实例。3. 实施流程Linux x86-64 上从解压到 apply 的完整命令序列3.1 解压与属主先定 owner 再谈其他补丁目录的位置有讲究不要放在 ORACLE_HOME 里面。opatch在检查空间和扫描文件时会把 ORACLE_HOME 下的内容当成 home 的一部分放在里面容易引发一些莫名其妙的判定。惯常做法是单独建一个/u01/patch按补丁号建子目录一个补丁一个位置回滚窗口期内不清理。# 全程用 ORACLE_HOME 的属主用户操作root 只在改属主时出现 export ORACLE_HOME/u01/app/oracle/product/11.2.0/dbhome_1 mkdir -p /u01/patch unzip -q p20760997_112030_Linux-x86-64.zip -d /u01/patch # 解压后先看属主和顶层结构 ls -ld /u01/patch/20760997 ls /u01/patch/20760997 # 应能看到 README.html、etc、files 等 # 如果 zip 是 root 传上来解压的改回来 chown -R oracle:oinstall /u01/patch/20760997 chmod -R 775 /u01/patch/20760997-q只是静默输出不影响解压结果。真正要留意的是别加-o覆盖同名目录——上一次失败留下的半旧files和这次的新文件混在一起opatch校验时会报文件校验和不符而你会以为是包坏了。每次打补丁前把旧目录改名或删掉是更省事的习惯。解压完成后第一件事是读 README 的两处补丁类型PSU 还是 one-off和最低 OPatch 版本要求。这两条决定了第 3.4 节走哪条路。3.2 用 lsinventory 和 prereq 把风险读出来打之前留一份基线出问题时才有对照物。基线至少包含三样lsinventory -detail的完整输出、已安装补丁号列表、以及数据库里无效对象的数量。cd $ORACLE_HOME/OPatch # 1. 当前工具与已装补丁基线 ./opatch version ./opatch lsinventory -detail /tmp/lsinv_before_$(date %Y%m%d).txt ./opatch lspatches # 老版本 OPatch 可能不支持报错可忽略 # 2. 冲突与空间预检只读可反复跑 ./opatch prereq CheckConflictAgainstOHWithDetail -ph /u01/patch/20760997 ./opatch prereq CheckSystemSpace -ph /u01/patch/20760997 ./opatch prereq CheckActiveFilesAndExecutables -ph /u01/patch/20760997 # 3. 数据库侧基线 sqlplus -s / as sysdba EOF select count(*) invalid_cnt from dba_objects where statusINVALID; select * from dba_registry_history order by action_time desc; exit EOF-ph后面接补丁目录的路径写绝对路径最稳有些 OPatch 版本对./的解析结果不理想。lsinventory -detail的输出要留着打完补丁后拿它和新的输出做 diff能一眼看出新增了哪个补丁号、哪些文件被替换。CheckActiveFilesAndExecutables报出的占用清单往往出乎意料——监控 agent、定时抽数脚本、甚至某个测试同学挂着的 sqlplus 会话都会让apply在复制库文件时失败。dba_registry_history在没打过 PSU 的库上可能是空的这正常它不是用来判断能不能打的而是打完之后的判据之一。无效对象数量这个基线更重要打完补丁后数字回到基线附近才算真正收尾。3.3 opatch apply参数、日志与中断处理到了这一步顺序不能乱先停应用再停监听最后停实例。反过来操作会让应用侧报一堆连接错误日志里混进无关噪音。# 1. 停应用、停监听、停实例 lsnrctl stop sqlplus -s / as sysdba EOF shutdown immediate; exit EOF # 2. 再确认一次没有残留进程占用 home ps -ef | grep -v grep | grep $ORACLE_HOME $ORACLE_HOME/OPatch/opatch prereq CheckActiveFilesAndExecutables -ph /u01/patch/20760997 # 3. 正式打补丁 $ORACLE_HOME/OPatch/opatch apply /u01/patch/20760997 \ -oh $ORACLE_HOME \ -log /u01/patch/apply_20760997.log echo exit code: $? # 4. 立刻核对登记结果 $ORACLE_HOME/OPatch/opatch lsinventory -detail | grep -i 20760997几个参数值得说清楚。-oh显式指定目标 home一台机器上有多个 home 时必须带否则opatch会用环境变量推断推断错了就是往另一个库上打。-log把日志落到你指定的位置默认日志在$ORACLE_HOME/cfgtoollogs/opatch/下按时间戳命名事后找起来麻烦。第一次打某个补丁不建议加-silent交互输出里会逐条打印正在替换的文件和阶段性结论比事后翻日志直观得多。RAC 或多节点共享 home 的场景opatch会检测到其他节点仍在使用此时需要加-local逐节点执行。惯常做法是所有节点先停实例逐节点打完全部成功后再统一启动——中途某个节点失败时至少不会出现“一半新一半旧”的二进制混跑。提示apply被 CtrlC 打断、SSH 断连、或机器重启之后不要立刻重跑。先执行opatch lsinventory -detail看补丁有没有被登记再对比$ORACLE_HOME/.patch_storage/20760997里的文件状态确认是“完全没开始”还是“做了一半”两种情况的处置方式完全不同。返回码 0 且输出里有成功字样才算二进制层面完成。但这只是前半程。3.4 补丁后处理catbundle 与 utlrp 的先后顺序二进制替换完成后数据库还起不来或者起来了带一堆无效对象这是最常见的“打完了但没用”的状态。11.2.0.3 上的处理分两条路。one-off 类补丁只做一件事重编译无效对象。PSU 类补丁多一步catbundle.sql它会往数据字典里写入补丁的登记信息并执行该 PSU 附带的 SQL 变更。顺序是先catbundle再utlrp。sqlplus -s / as sysdba EOF -- 仅 PSU 需要one-off 跳过这一段 ?/rdbms/admin/catbundle.sql psu apply -- 重编译无效对象跑两遍更稳 ?/rdbms/admin/utlrp.sql ?/rdbms/admin/utlrp.sql -- 三项收尾核对 select * from dba_registry_history order by action_time desc; select count(*) invalid_cnt from dba_objects where statusINVALID; select * from v$version; exit EOFutlrp跑两遍是有原因的第一遍编译过程中某些对象的依赖顺序会导致新的一批对象失效第二遍把剩下的收干净。RAC 环境下只需要在一个实例上执行脚本内部有并发调度。跑完之后dba_objects里的无效对象数量应该回到第 3.2 节记下的基线附近如果反而变多说明catbundle那一步出了问题或者补丁本身有前置条件没满足。最后一处极易误判打完 PSU 后v$version显示的版本号通常不变还是 11.2.0.3.0.x。PSU 不修改版本号只更新 inventory 和dba_registry_history。所以“版本号没变是不是没打上”这个疑问正确判据是opatch lsinventory里有没有这个补丁号以及dba_registry_history里有没有对应记录。搞错判据的后果是重复打补丁第二次会因为冲突检查失败而卡住。到这里可以启动监听和实例让应用做一轮冒烟。冒烟范围按补丁说明里的“已知变更”来定重点覆盖存储过程、物化视图刷新和统计信息收集这几类依赖数据字典的路径。4. 回滚预案opatch rollback 之前必须准备好的三样东西4.1 备份清单ORACLE_HOME 之外更要备份什么opatch rollback只能撤销二进制层面的改动它不会把catbundle写进数据字典的东西还原回去。理解这一点回滚预案才有意义。真正能兜底的是补丁窗口之前准备好的这几样东西。对象命令或动作为什么必须有数据库全备 归档RMAN 备份记录起始 SCN回滚无法撤销字典变更这是唯一彻底后悔药参数文件create pfile/u01/backup/pfile_before.ora from spfile;补丁后起不来时先看参数是否被改控制文件 tracealter database backup controlfile to trace as /u01/backup/ctl_before.sql;极端情况下的重建依据inventory 目录cp -a $ORACLE_HOME/inventory /u01/backup/inventory 损坏后手工修复的参照补丁前 lsinventory第 3.2 节的输出文件比对差异、确认登记状态.patch_storage现状du -sh $ORACLE_HOME/.patch_storage回滚依赖它里面的原始文件备份不需要整目录cp -a一个几百 G 的 ORACLE_HOME但.patch_storage一定不能清。这个目录里存着被替换文件的原始副本opatch rollback就是靠它还原。有些“清理磁盘空间”的脚本会把它当垃圾删掉删完回滚能力就没了只能走重装 home 加 RMAN 恢复那条重路。4.2 opatch rollback 的触发条件与命令什么时候该回滚我的判断标准是三条之一补丁后关键业务 SQL 出现无法绕过的性能回退实例反复 Crash 且 trace 指向补丁变更的模块utlrp反复执行后无效对象数量仍显著高于基线且定位不到具体对象。三种情况都不是“再观察一天”能解决的。# 前提实例与监听已停进程占用检查同 apply $ORACLE_HOME/OPatch/opatch rollback -id 20760997 \ -oh $ORACLE_HOME \ -log /u01/patch/rollback_20760997.log # 确认登记已移除应该没有输出 $ORACLE_HOME/OPatch/opatch lsinventory -detail | grep -i 20760997 # PSU 类补丁回滚后注册表记录需要按 README 的 rollback 段落处理 sqlplus -s / as sysdba EOF select * from dba_registry_history order by action_time desc; exit EOF-id用补丁号不是文件名也不是解压出来的目录名。回滚成功后lsinventory里不应该再有这个编号。PSU 的回滚动作比 one-off 复杂README 里通常单独有一节讲回滚后注册表怎么对齐不同 PSU 的处理脚本不完全一样照着那份文档走比自己猜稳妥。4.3 .patch_storage 与 inventory 不一致的兜底apply或rollback中途失败后最容易遇到的是 inventory 状态不一致lsinventory报损坏、opatch报中央 inventory 被锁、或者补丁号登记了但文件其实没换全。排查顺序建议这样走。先看有没有残留锁。opatch异常退出会在 inventory 目录或.patch_storage下留下锁文件确认没有任何opatch进程在跑之后把锁清掉再试。这一条能解决相当一部分“inventory 被锁”的报错。再看文件实际状态$ORACLE_HOME/.patch_storage/20760997/下通常能看到原始文件副本和替换后的文件逐个比对关键库文件的时间戳和大小判断补丁究竟做完了多少。如果 inventory 已经损坏到opatch完全读不出来就不要在线上继续折腾了。用 4.1 备份的 inventory 目录做参照修复或者从同版本的备份 home 恢复文件再用 RMAN 把库拉回补丁前的状态。这条路慢但确定性最高。这也是为什么我一直坚持补丁窗口必须留出完整的备份时间而不是“先把补丁打了备份明天做”。5. 避坑与排查五条踩过的记录5.1 安装阶段权限、OPatch 版本、空间现象一opatch apply一上来就报补丁不适用于当前 home。原因通常不是包坏了而是三处之一版本位对不上库是 11.2.0.4 却拿了 11.2.0.3 的包、-oh指到了另一个 home、或者opatch读的是/etc/oraInst.loc里登记的另一套 inventory。解决方式是按顺序排除先uname -m确认平台位再opatch lsinventory确认它正在读哪个 home 和哪个版本最后用-oh加-invPtrLoc双重显式指定。多 home 机器上执行前先echo $ORACLE_HOME别信自己记得住。现象二补丁刚启动就退出日志里有版本检查失败的痕迹。原因就是 OPatch 太老。解决方法是按 2.2 的步骤替换整个 OPatch 目录停进程、旧目录改名备份、解压新目录、递归改属主、opatch version与opatch lsinventory双验证。这里有个容易忽略的细节——lsinventory能跑通才算升级成功只看到版本号变了不算因为新版 OPatch 有可能读不动旧 inventory 的格式。现象三CheckSystemSpace显示通过apply跑到一半报错退出inventory 状态不明。原因一般是.patch_storage的备份空间没算进去加上/tmp和 ORACLE_HOME 同盘被日志吃满。解决方法是打之前按 ORACLE_HOME 体积的 1.5 倍预留并把opatch日志目录指到独立盘。已经失败了就不要直接重跑先做 4.3 那套状态确认判断是“完全没开始”还是“做了一半”再决定重试还是回滚。5.2 生效阶段实例没停干净、对象没重编译现象四CheckActiveFilesAndExecutables报若干.so仍被占用或者apply在复制库文件时报可执行文件未关闭。原因往往是“我以为停了”。数据库实例停了但另一节点的实例还在跑或者监控 agent、定时抽数脚本、某个人挂着的 sqlplus 会话仍然链着$ORACLE_HOME/lib下的库。解决方式是用ps -ef | grep $ORACLE_HOME和fuser -v $ORACLE_HOME/lib/libclntsh.so逐个揪出来把 agent 和 crontab 里的任务临时停掉。RAC 场景下必须所有节点一起停单独停一个节点去打补丁冲突检查那关就过不去。现象五补丁打成功了实例也起来了应用一连就报对象失效类的错误。原因基本是两个utlrp没跑或者 PSU 漏了catbundle.sql。解决方法是先查当前无效对象数量和 3.2 记下的基线比再查dba_registry_history看有没有本补丁的登记记录。缺catbundle的补上再跑utlrp跑两遍个别顽固对象用alter procedure/package ... compile手工编译。这里有个反直觉的点——utlrp执行过程中报出一些编译错误是正常的它会把编译失败的记录留在utlrp的输出里重点看最终统计的无效对象数量而不是中途的报错条数。6. 进阶把一次打补丁做成可复用的清单与预检脚本单次打补丁靠记性长期打补丁要靠清单。手里同时维护几套库的人最容易犯的错不是技术问题而是“上一次是怎么打的”记不清了。我的做法是给每个补丁建一行台账字段固定跨版本复用。字段本例填写用途补丁号20760997rollback -id、.patch_storage定位版本位 / 平台位112030 / Linux-x86-64与目标 home 比对防止打错包补丁类型PSU 或 one-off决定是否跑catbundle最低 OPatch按 README 填写提前安排工具升级前置动作停实例、停监听、全备、记基线估算窗口长度后置动作catbundleutlrp×2收尾清单验证判据lsinventory、registry_history、无效对象数判定成功与否回滚窗口全备 SCN 保留.patch_storage事故止损期限台账之外预检部分完全可以脚本化。下面这个脚本把第 2、3 章里那些只读检查串起来在补丁窗口开始前跑一遍输出一份可直接贴进变更单的报告。#!/bin/bash # precheck.sh ORACLE_HOME PATCH_DIR set -u OH${1:?usage: precheck.sh ORACLE_HOME PATCH_DIR} PD${2:?usage: precheck.sh ORACLE_HOME PATCH_DIR} OP$OH/OPatch/opatch echo 1. 平台与版本 uname -m $OP version echo 2. 当前已装补丁基线 $OP lsinventory -detail /tmp/lsinv_$(date %Y%m%d_%H%M).txt grep -i Oracle Home /tmp/lsinv_$(date %Y%m%d_%H%M).txt echo 3. 冲突 / 空间 / 占用 for chk in CheckConflictAgainstOHWithDetail CheckSystemSpace CheckActiveFilesAndExecutables; do echo --- $chk $OP prereq $chk -ph $PD 21 | tail -20 done echo 4. 文件系统余量 df -h $OH /tmp echo 5. 数据库侧基线实例运行时才有意义 sqlplus -s / as sysdba EOF set pagesize 100 linesize 160 select count(*) invalid_cnt from dba_objects where statusINVALID; select patch_id, action, action_time from dba_registry_history where rownum 10 order by action_time desc; exit EOF脚本本身没有技术含量价值在于“每次跑的都是同一套检查”。人肉检查的问题是顺序会变、项会漏尤其是窗口紧张的时候最先被跳过的往往就是冲突检查这一项。脚本里三个prereq用循环跑输出截取尾部二十行足够看到结论数据库侧那段用set pagesize保证输出不被折行打断方便直接复制进变更记录。两个可以继续加强的点把lsinventory的输出文件按“补丁号_时间”命名归档形成一台机器的补丁时间线把无效对象数量写进一个固定文件长期看这条曲线某些补丁导致的隐性回退会提前暴露。从那以后我每次打补丁前都强制走一遍这三步跑预检脚本留基线、确认.patch_storage空间和备份就绪、把补丁台账那一行先填好再动手。花的是十五分钟省下的通常是凌晨四点还在对着lsinventory猜状态的那几个小时。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑