简介:面向Oracle数据库11.2.0.4版本发布、适用于Linux 64位平台的PSU补丁包(补丁标识p33477185),核心用途是帮助数据库管理员与运维人员修复已知安全漏洞、改善系统稳定性并提升运行效率。压缩包共三千六百五十八个文件,其中so动态共享库和o编译目标文件构成补丁的二进制主体,大量XML元数据用于描述补丁依赖与安装条件,SQL脚本负责执行数据字典更新,另有JAR模块辅助Java组件集成,整体压缩包约四百三十六兆字节。已有八百五十九人学习/下载该资源。通过这份补丁包,读者可获得Oracle 11.2.0.4在Linux 64位环境下的完整官方补丁内容,作为离线升级与安全加固的介质;包内结构接近Oracle官方补丁发布形态,便于自动部署脚本提取调用,也可借助元数据快速核对适用版本,降低生产环境升级风险。整个包体覆盖补丁应用所需的二进制、校验和与配置信息,适合有经验的DBA进行受控更新。
1. 别再让安全扫描卡在数据库补丁上:这个 2022 年 1 月的 PSU 包到底解决了什么
很多公司还在跑 11.2.0.4 的 Oracle 数据库,等保、漏洞扫描、渗透测试的报告一来,DBA 就得面对一句灵魂拷问:数据库补丁怎么还没打?如果你手上的库是 Linux x86-64 平台,大概率会碰到标题里这个 p33477185(文档名里的 220118 对应 2022 年 1 月的季度发布批次)。它是一个完整的数据库 PSU 补丁集,作用是一次补齐从上一个 PSU 到这次发布之间所有已公开的高危漏洞和一批高频 bug,而且是累积式的,之前没打的更新也在里面。适合谁:手上有 11.2.0.4 生产库、被安全报告追着跑、或者因为某些诡异 bug 一直靠一次性补丁撑着的人。这篇文章把从准备、安装、RAC 滚动到回滚验证的全过程拆开讲。
2. 打 PSU 前的三件准备工作:版本核对、备份与基线检查
PSU 安装本身不复杂,真正翻车的场景几乎都出在准备阶段。我见过不少人直接解压就 apply,结果先是 OPatch 版本太老被 precheck 拦下,然后发现库里还挂着一个冲突的 one-off patch,最后硬着头皮回滚。准备阶段花 40 分钟,后面能省出 4 个小时的维护窗口。
2.1 确认补丁包与当前 OPatch 版本:版本不匹配连 precheck 都过不去
标题里的 11.2.0.4.220118 是个很规范的命名:11.2.0.4 是产品版本基线,220118 表示 2022 年 1 月 18 日左右的发布批次,p33477185 是 My Oracle Support 上的补丁号。MySQL 用户可能不熟悉这种命名,但数据库 DBA 一看就知道这是季度 PSU,一年四个,1 月、4 月、7 月、10 月各一个。因为是累积式的,只要当前库的补丁版本不高于 220118,就能直接安装。
在动手之前,先确认 OPatch 版本。很多旧环境的 OPatch 还停在 11.2.0.3.x 早期版本,而新版 PSU 的 precheck 会直接检查 OPatch 是否满足最低要求。打开终端执行:
# 查看当前 OPatch 版本,确认是否满足补丁包 Readme 里的最低要求 $ORACLE_HOME/OPatch/opatch version # 如果 OPatch 版本过老,先从官方支持平台下载适用于 11.2.0.4 的 OPatch 升级包 unzip p6880880_112000_Linux-x86-64.zip -d /u01/opatch_new # 保留旧目录作为后悔药,再把新目录替换回去 mv $ORACLE_HOME/OPatch $ORACLE_HOME/OPatch.bak mv /u01/opatch_new/OPatch $ORACLE_HOME/OPatch # 替换后必须修正属主,否则后续 opatch 命令会报权限问题 chown -R oracle:oinstall $ORACLE_HOME/OPatch这里 mv 保留 OPatch.bak 是为了万一新 OPatch 不兼容还能退回。chown 属主这一步很多人会忘,用 root 解压后整个目录归 root 所有,oracle 用户跑 opatch 时直接读取失败。判断版本是否够用,最简单的方式是直接看补丁包里的 README.txt,里面有明确的“OPatch version must be X or later”,不要凭感觉。
2.2 备份是后悔药:冷备与一致性检查的底线
打 PSU 有一个非常容易被忽略的底层事实:opatch apply 替换的是二进制文件,这部分可以 rollback;但补丁包里带的数据字典更新脚本 catbundle.sql 一旦执行,涉及 SYSTEM 表空间里的字典对象变更,没有对应的自动回滚脚本。也就是说,如果你跑了 catbundle 之后发现问题,想靠 opatch rollback 恢复原状,多半会失败。
所以备份策略的底线是:至少保证数据库软件和数据库文件都能恢复到打补丁之前。对于中大型生产库,最省事也最可靠的备份方式是冷备。停库后把关键目录和文件原样复制走,具体命令如下:
# 以 sysdba 身份关闭数据库,保证文件处于一致状态 sqlplus / as sysdba SQL> shutdown immediate; SQL> exit; # 创建备份目录,并复制参数文件、密码文件和数据库文件 mkdir -p /backup/db_202201 cp -a $ORACLE_HOME/dbs /backup/db_202201/dbs cp -a /u01/app/oradata/orcl /backup/db_202201/oradatacp -a 会保留文件属主、权限和时间戳,这比 cp -r 更适合做这种一致性备份。如果数据库文件很大,可以用 tar 或 rsync 替代直接复制,但核心思路一致:关闭数据库后复制,不能在 open 状态下复制数据文件,否则文件头不一致。如果库大到冷备窗口撑不住,退而求其次用 RMAN 做一个全备份,然后打补丁期间把归档日志也备份好,但不建议没有 RMAN 备份就直接打补丁。
2.3 用 opatch lsinventory 摸清当前基线
安装新补丁前,需要知道这库曾经打过什么。oracle 用户执行以下命令:
# 查看当前数据库软件已安装的补丁清单 $ORACLE_HOME/OPatch/opatch lsinventory # 如果想看更详细的补丁描述,可以加 -detail 参数再过滤 $ORACLE_HOME/OPatch/opatch lsinventory -detail | grep -i "patch description"lsinventory 会输出当前 ORACLE_HOME 下已经应用的所有补丁,包括 PSU 和 one-off patch。重点看两件事:一是是否已经存在比 11.2.0.4.220118 更新的 PSU,如果存在就不要再打了,因为 PSU 是累积的,旧包没必要重复安装;二是有没有 one-off patch,这些临时补丁很容易与 PSU 里的内容冲突,后面第 5 章细说。
这一步也能顺便验证 OPatch 能否正常读取 inventory。如果 lsinventory 报找不到 inventory 或权限错误,说明安装清单本身就有问题,先解决这个再往下走,否则 apply 时大概率同样失败。
3. 单实例环境从解压到跑完 SQL:一条完整的 PSU 安装链路
准备做完,下面进入正式安装。这里以单实例数据库为例,RAC 的差异在第 4 章单独给。整个流程可以概括成四句话:解压补丁、关闭数据库、opatch apply、执行 catbundle.sql。每一句都有对应的命令和容易踩的坑。
3.1 解压补丁包与检查 Readme:先看文档再动手
补丁包下载下来通常是一个 zip 文件,命名类似 p33477185_112040_Linux-x86-64.zip。解压前先确认磁盘空间,解压后的目录占用大概 1 到 2 GB,别解到一半报 disk full。建议解压到一个独立目录,不要直接解到 ORACLE_HOME 里面,这样后续回滚时路径更清晰。
# 创建补丁目录,统一放到 /u01/patch 下 mkdir -p /u01/patch # 解压补丁包,-d 参数指定解压目 unzip p33477185_112040_Linux-x86-64.zip -d /u01/patch/ # 修正属主:补丁文件必须能由 oracle 用户读写 chown -R oracle:oinstall /u01/patch # 解压后查看目录结构,并阅读 Readme ls -l /u01/patch/33477185/ less /u01/patch/33477185/README.txt压缩包内的目录名是补丁号 33477185,opatch 后面就是通过这个目录来找补丁内容的。Readme 里的关键信息包括:适用的具体版本、OPatch 最低版本要求、是否支持滚动安装、安装前置条件,以及是否有 root 需要执行的附加脚本。我习惯先把 Readme 从头到尾读一遍,因为同一个补丁号在不同小版本上的安装步骤会有细微差别。
3.2 关闭实例和监听:让二进制替换发生在无人使用的时候
opatch apply 会直接替换 ORACLE_HOME 下的可执行文件和动态库。如果数据库实例还在运行,相当于程序正在使用要被替换的文件,结果不可控。所以单实例场景下必须先停库,这一步没有捷径。
# 以 sysdba 身份关闭数据库实例 sqlplus / as sysdba SQL> shutdown immediate; SQL> exit; # 关闭监听,避免新的连接进来 lsnrctl stop # 如果配置了 dbconsole 或云控代理,也一并停掉 $ORACLE_HOME/bin/emctl stop dbconsoleshutdown immediate 会等待当前事务回滚完成,如果应用还有大量活动会话,可能耗时较长。我一般会在变更窗口前让应用团队先停止业务流量,再执行 shutdown。万一 immediate 卡住,可以检查 v$session 里还有哪些活动会话,与业务确认后处理,不要轻易 shutdown abort,除非你接受实例恢复的代价。
停完库后顺手确认一下没有残留的 oracle 进程:
# 确认没有 ora_ 开头的数据库后台进程残留 ps -ef | grep ora_ | grep -v grep如果有残余进程,多半是后台 job 或外部连接触发的进程,需要先找到来源再处理。强行 kill 进程属于最后手段,正常停库流程不该走到这一步。
3.3 执行 opatch apply:参数记牢这三个就够
确认实例和监听都停了,切换到补丁目录,执行 apply。命令本身不复杂,但参数要写对:
# 进入补丁目录,执行 apply cd /u01/patch/33477185 $ORACLE_HOME/OPatch/opatch apply -oh $ORACLE_HOME -phBaseDir /u01/patch/33477185如果当前系统里存在多个 ORACLE_HOME,或者 oraInst.loc 默认路径不对,需要加上 -invPtrLoc 参数指定清单文件位置,比如 -invPtrLoc /etc/oraInst.loc。不过多数单实例环境不需要加这一步,opatch 能自动找到清单。
apply 阶段会有大量输出,最关心的无非两个结果:成功时末尾会出现一行类似 Apply Patch Completed Successfully,失败时会回显具体的错误提示并停在某一步。整个 apply 过程通常 10 到 30 分钟,取决于磁盘速度和 ORACLE_HOME 的大小。如果超过一小时没动静,去看 $ORACLE_HOME/cfgtoollogs/opatch/ 下的日志文件,不要盲目中断进程。
这里强调一个操作纪律:用 oracle 用户执行 opatch,不要用 root,也不要用 sudo。用 root 执行会导致新替换的文件属主变成 root,后续数据库进程启动时直接权限报错。
3.4 catbundle.sql 不能省:数据字典更新才是补丁的另一半
opatch apply 成功只代表二进制替换完成。PSU 里还包含一批 SQL 脚本,用来更新数据字典和相关存储过程的状态,这一步通过 catbundle.sql 完成。很多第一次打 PSU 的人会在这一步漏掉,直接启动数据库,结果版本不一致,报错时才发现数据字典还是旧状态。
执行方式如下:
# 进入 rdbms/admin 目录,这里的 catbundle.sql 是数据库自带的脚本 cd $ORACLE_HOME/rdbms/admin # 以 sysdba 连接并启动数据库(如果尚未启动) sqlplus / as sysdba SQL> startup; SQL> @catbundle.sql PSU apply注意 @catbundle.sql 后面的两个参数:PSU 表示补丁类型,apply 表示执行安装动作。如果是回滚场景会写成 @catbundle.sql PSU rollback。脚本执行期间会输出大量 DDL 和 PL/SQL 信息,时间从十几分钟到几小时不等,取决于数据库对象规模。
执行前务必保证没有其他会话占用系统对象,不然容易遇到 ORA-04021 之类的锁等待错误。可以在执行前查一下 v$session,只保留自己的会话。执行结束后查看输出末尾有没有明显报错,并把 spool 日志保存下来。
提示:catbundle.sql 是补丁能否真正生效的分水岭。只跑 opatch apply 而跳过 catbundle,数据库内部仍然是旧版本状态,后续查询 dba_registry_sqlpatch 也不会出现对应的记录。
4. RAC 环境打 PSU:滚动补丁让两个节点轮流值班
单实例的流程跑熟以后,RAC 环境也不复杂,但节奏完全不同。如果你的库是 RAC,打补丁时重点考虑两个问题:能不能滚动、怎么保证两个节点版本一致。
4.1 为什么 RAC 优先选滚动方案
11.2.0.4 的 PSU 支持滚动安装,意思是同一个集群里的节点可以逐个打,不需要停整个集群。好处很明显:打第一个节点时,第二个节点还在对外提供服务,业务中断窗口大幅缩短。代价是操作步骤变多,而且对操作顺序有严格要求。
如果选非滚动方式,所有节点同时打,需要先把整个集群停掉,相当于把单实例的停机时间拉长,一般情况下不推荐。所以本文只讲滚动方案。另外要注意的是,RAC 环境通常伴随 Grid Infrastructure,11.2.0.4 的 Grid Home 补丁和 Database Home 补丁是分开的两个补丁号。本文讨论的 p33477185 属于 Database Home 的 PSU,如果 Grid 版本也需要更新,请按对应的 GI PSU 文档单独处理,不要在数据库补丁的流程里混着做。
4.2 节点一操作:停实例、打补丁、启动实例
假设集群有两个节点,数据库服务名为 orcl,节点一叫 node1,节点二叫 node2。第一步操作节点一:
# 只停止节点一上的实例,节点二继续对外服务 srvctl stop instance -d orcl -i orcl1 # 确认集群里节点一上的实例确实已停止 srvctl status database -d orcl # 在节点一上执行 opatch apply,命令与单实例一致 cd /u01/patch/33477185 $ORACLE_HOME/OPatch/opatch apply -oh $ORACLE_HOME -phBaseDir /u01/patch/33477185 # 打完二进制后,立即把节点一的实例拉起来 srvctl start instance -d orcl -i orcl1srvctl 是 RAC 环境下管理实例启动停止的标准工具,不要再用 sqlplus shutdown 去停单个 RAC 实例,srvctl 会同步更新集群资源状态。在 node1 打补丁期间,node2 仍持有数据库资源,所以节点一的实例停止后,集群里客户端连接会自动落在节点二上。
这里有个顺序问题:节点一 opatch apply 完成后,数据库字典更新脚本 catbundle.sql 要不要在节点一上立刻执行?我习惯不在节点之间跑 catbundle,因为数据字典是共享的,两个节点版本一致后跑一次就好。如果先在一个节点跑了 catbundle,另一个节点还是旧二进制,短时间内集群内版本不一致,反而增加风险。
4.3 节点二重复操作与最终验证
节点一的实例重新启动并恢复正常后,切换到节点二重复同样的动作:
# 停止节点二上的实例 srvctl stop instance -d orcl -i orcl2 # 在节点二上执行 opatch apply cd /u01/patch/33477185 $ORACLE_HOME/OPatch/opatch apply -oh $ORACLE_HOME -phBaseDir /u01/patch/33477185 # 恢复节点二上的实例 srvctl start instance -d orcl -i orcl2两个节点的二进制都替换完成并启动实例后,再在任意一个节点上执行 catbundle.sql 更新共享数据字典。这一步只需要执行一次,不要每个节点都跑:
# 在 node1 上执行一次即可 cd $ORACLE_HOME/rdbms/admin sqlplus / as sysdba SQL> @catbundle.sql PSU apply跑完脚本后,两个节点的实例都是基于新二进制运行,数据字典也更新到对应版本,整个 RAC 滚动补丁才算收尾。执行 catbundle 期间最好保持集群稳定,避免节点切换或 rebalance 操作,减少干扰。
5. 打 PSU 最容易翻车的五个场景:现象、原因与定位方法
补丁安装这事,文档读得再熟也挡不住环境差异。这里整理五个我见过或处理过的典型问题,每一条都按现象、原因、解决思路来说。
5.1 precheck 卡在 OPatch 版本过老
现象:opatch apply 执行后很快退出,屏幕提示 OPatch version is older than the minimum required version,或者 precheck 步骤直接标红失败。
原因:新 PSU 对 OPatch 版本有硬性要求,早期版本不支持新补丁包的内部格式和检测逻辑。很多环境从 2018 年以后就没升过 OPatch,自然过不了这关。
解决:按第 2.1 节的操作升级 OPatch,替换后重新执行 opatch version 确认版本号满足要求,再跑 apply。升级 OPatch 不会影响已安装的补丁记录,只是替换工具本身,所以可以随时进行。
5.2 实例没关干净,apply 直接报文件占用或环境错误
现象:apply 过程中报 Error while creating file 或者提示无法覆盖某动态库,也可能报 HOME 目录下存在活动进程。
原因:数据库实例停了,但监听没停,或者后台还有残留的 oracle 服务进程;也有可能是 Grid 管理下的实例通过 srvctl 停了,但某个 agent 进程还挂在 ORACLE_HOME 下。
解决:先执行 ps -ef | grep ora_ 检查残留进程,再 lsnrctl status 查看监听状态。如果确实有进程占着文件,确认来源后处理后重新 apply。养成习惯:单实例打 PSU 前把监听和 dbconsole 一起停掉,RAC 节点用 srvctl 停实例后,也顺手看一眼节点上有没有跑着的进程。
5.3 曾经打过的一次性补丁造成冲突
现象:apply 时提示 Patch xxx conflicts with the patch(es) already applied,列出的补丁通常是从前 DBA 为了修某个局部 bug 打的 one-off patch。
原因:PSU 是累积补丁集,本身包含了历史修复内容。如果某个 one-off patch 的修复内容被 PSU 覆盖,就会触发冲突检测,opatch 宁可拒绝安装也不允许两套修复并存。
解决:先用 opatch lsinventory -detail 找出冲突的补丁号,执行 opatch remove 移除这个 one-off patch,然后重新 run apply。移除 one-off patch 前建议备份相关日志,并确认这个补丁修复的问题是否已经被 PSU 包含,避免修了一个 bug 又引入另一个。
5.4 catbundle.sql 执行到一半报错,库里却没有明显变化
现象:catbundle.sql 执行一段时间后输出一堆 ORA- 错误,比如 ORA-04021 或 ORA-01652,脚本中断退出。查询 dba_registry_sqlpatch 时既能看到 ACTION=APPLY 的行,但 STATUS 不是 SUCCESS。
原因:常见三类,一是表空间满,SYSTEM 或 SYSAUX 没有足够空间扩展;二是其他会话占用对象,导致 DDL 拿不到锁;三是 undo 表空间不足,脚本里的事务回滚失败。
解决:先看 spool 日志里的第一个错误是什么,按错误类型处理。表空间满就扩容,锁冲突就排查 v$session 里阻塞源,undo 不足就加 undo 表空间。处理完后不能直接简单重跑 catbundle.sql,需要先确认上次执行是否留下半截字典变更,必要时联系技术支持确认下一步。
5.5 打完后实例启动报内部错误或权限异常
现象:数据库启动时报 ORA-00600 [xxx] 之类的内部错误,或者直接报权限不足,检查 ORACLE_HOME 下新替换的文件属主是 root。
原因:最常见的是 opatch apply 用 root 执行了,或者补丁解压后属主没有修正。文件权限不对会影响数据库进程读取动态库和执行文件。
解决:用 root 或 oracle 用户执行 chown -R oracle:oinstall $ORACLE_HOME,修正属主后重新尝试启动。如果启动还是报内部错误,考虑二进制替换不完整,重新执行一次 opatch apply 覆盖安装。不要一上来就回滚,先排查属主和权限问题更划算。
6. 验证补丁生效与快速回滚:两条命令加一张表
补丁打完,别急着宣布结束,先做两件事验证:一是确认 OPatch 清单里有这个补丁,二是确认数据字典层面也记录了这个补丁。两个层面缺一不可。
# 验证二进制层面:opatch 清单里应能看到 33477185 $ORACLE_HOME/OPatch/opatch lsinventory -detail | grep 33477185 # 验证数据字典层面:dba_registry_sqlpatch 应出现一条 PSU 记录 sqlplus / as sysdba SQL> select patch_id, action, status, bundle_series from dba_registry_sqlpatch;opatch lsinventory 输出的是 ORACLE_HOME 下二进制层面的补丁记录,只要 apply 成功就一定有。dba_registry_sqlpatch 则是数据库内部记录 SQL 变更的系统视图,只有 catbundle.sql 成功执行后才会出现对应行,status 正常显示 SUCCESS。两条都确认达标,补丁才算真正打完。
如果打完发现问题需要回滚,先权衡:catbundle.sql 没有执行或者没有产生任何实际字典变更时,可以直接用 opatch rollback 把二进制退回旧版本:
# 回滚二进制补丁,-id 指定补丁号,-phBaseDir 指定补丁所在目录 $ORACLE_HOME/OPatch/opatch rollback -id 33477185 -phBaseDir /u01/patch/33477185一旦 catbundle.sql 已经执行并提交,数据字典层面就没有简便的回滚路径。这种时候 opatch rollback 只会把二进制退回旧版,字典还是新状态,两边版本不匹配,问题更严重。所以我的习惯是:在跑 catbundle.sql 之前,先把 opatch apply 完成后的数据库正常启动一次,确认基础功能没问题,再执行数据字典更新;字典更新完成后就不再轻易尝试二进制回滚,而是依靠第 2.2 节的备份做恢复。之前在某生产环境打补丁,我先做完二进制替换,临时有事离开窗口,回来直接启动了数据库忘了跑 catbundle,第二天应用反馈存储过程行为异常,查询 dba_registry_sqlpatch 才发现漏了关键一步,只能重新执行 catbundle 才恢复。那次之后我给自己定了规矩:opatch apply 结束先不着急走,当场把 catbundle 和验证命令全部跑完,确认 dba_registry_sqlpatch 出现 SUCCESS 记录才关窗口。希望帮到你。
本文还有配套的精品资源,点击获取