☰
Oracle 12c Windows 补丁实战:Opatch 避坑与完整流程
2026/10/29 16:45:47 网站建设 项目流程

简介:面向 Windows 平台 Oracle 12c 数据库运维与升级场景的 OPatch 补丁工具包,适合需要为数据库打补丁、排查补丁冲突或搭建测试环境的 DBA 与系统管理员使用。压缩包共 454 个文件,约 102.88MB,以 132 个 jar、111 个 dll、21 个 exe 等可执行与库文件为核心,辅以 27 个 properties 配置、18 个 pl 脚本、9 个 pm 与 9 个 sh 脚本,以及 bat、cmd 批处理入口和 md、txt 说明文档,构成完整的补丁应用与校验工具链。已有 999 人学习下载,说明其在同类场景中具备一定参考价值。包内保留 opatch、datapatch、opatchauto 等批处理入口及 blacklist、cacerts、casfile 等配置资源,便于读者直接部署补丁工具、执行补丁冲突检查与回滚操作,并借助说明文档理解各组件用途,减少在 Windows 环境下升级 Oracle 12c 时的试错成本。

1. 补丁打不上,多半不是 Opatch 的锅

Windows 上给 Oracle 12c 打补丁,翻车现场往往长一个样:opatch apply跑完报Patch 12345678 failed to apply,或者卡在Prerequisite check "CheckActiveFilesAndExecutables" failed,再或者补丁明明显示成功,数据库起来后dba_registry_sqlpatch里查不到记录。很多人第一反应是 Opatch 版本不对,换一个再试,结果越换越乱。实际上在 Windows 平台,补丁失败的高频原因集中在三处:Opatch 与补丁要求的版本不匹配、Oracle 服务没停干净导致文件被占用、以及ORACLE_HOME环境变量指向了错误的实例。这份资源围绕 Oracle 12c 在 Windows 下的 Opatch 补丁操作展开,覆盖 Opatch 版本核对、补丁冲突检查、停库停服务、apply 与 rollback 的完整链路,适合需要在 Windows 环境维护 12c 单实例或 RAC 节点的 DBA 照着复现。下面按“先确认工具链、再动手打、最后验证与回退”的顺序拆开讲,中间穿插我踩过的坑。

2. Opatch 工具链核对:版本、环境变量与补丁前置检查

补丁打不上的第一道坎,往往在动手之前就埋下了。Oracle 12c 的补丁(尤其是 PSU、CPU 以及后来的 Release Update)对 Opatch 最低版本有硬性要求,补丁包里README.html或etc/config/inventory.xml会写明OPatch Version的下限。Windows 下 Opatch 的路径是%ORACLE_HOME%\OPatch,执行opatch version就能看到当前版本。如果低于补丁要求,必须先升级 Opatch 本身——注意,升级 Opatch 是“替换目录”,不是“打补丁”,顺序搞反会直接导致后续 apply 报OPatch found the word "error" in the stderr of the make command这类误导性错误。

2.1 确认 Opatch 版本与 ORACLE_HOME 指向

先开一个以管理员身份运行的 cmd(Windows 下权限不足会导致 inventory 读取失败,报Unable to read inventory),然后逐条确认环境。这里的关键是ORACLE_HOME必须指向你要打补丁的那个 home,而不是系统里另一个实例的 home——多实例机器上这是最常见的翻车点。

:: 以管理员身份打开 cmd,先看环境变量指向 echo %ORACLE_HOME% echo %ORACLE_SID% :: 进入 Opatch 目录并查版本 cd /d %ORACLE_HOME%\OPatch opatch version :: 查看当前 home 已安装的补丁列表,记下 patch id 和版本 opatch lspatches

逻辑说明:echo %ORACLE_HOME%用来确认当前 shell 继承的 home 路径,Windows 下环境变量可能是系统级也可能是用户级,两者冲突时以当前 shell 为准。opatch version输出形如OPatch Version: 12.2.0.1.17,拿这个版本号去比对补丁 README 里的最低要求。opatch lspatches列出已打补丁,输出里每个补丁有Patch ID和Description,打新补丁前先看有没有冲突补丁已经装过——如果目标补丁的前置补丁(prerequisite)没装,apply 会在 prereq 阶段直接失败。

参数说明:opatch lspatches在 12c 上默认读%ORACLE_HOME%\OPatch\opatch下的 inventory,不需要额外参数;如果 home 是只读挂载或权限异常,加-oh %ORACLE_HOME%显式指定。opatch version没有业务参数,纯粹读本地 jar 版本。

2.2 用 opatch prereq 做补丁前置检查

补丁解压后(假设解压到D:\patch\p32876319_122010_MSWIN-x86-64),不要急着 apply,先跑 prereq 检查。这一步能把“补丁与当前 home 不匹配”“补丁冲突”“空间不足”等问题提前暴露,比 apply 失败后再回滚省事得多。

:: 进入补丁解压目录 cd /d D:\patch\p32876319_122010_MSWIN-x86-64 :: 检查补丁是否适用于当前 home(CheckPatchApplicableOnCurrentPlatform 等) opatch prereq CheckPatchApplicableOnCurrentPlatform -phBaseDir . -oh %ORACLE_HOME% :: 检查补丁冲突(是否与已装补丁冲突) opatch prereq CheckConflictAgainstOHWithDetail -phBaseDir . -oh %ORACLE_HOME% :: 检查是否有文件被占用(Windows 下重点看这个) opatch prereq CheckActiveFilesAndExecutables -phBaseDir . -oh %ORACLE_HOME%

逻辑说明:-phBaseDir .表示以当前目录为补丁根目录,-oh显式指定目标 home。CheckConflictAgainstOHWithDetail会输出冲突补丁列表,如果提示Conflicts with patch 3xxxxxxx,说明目标补丁与已装补丁有文件级重叠,需要先确认补丁 README 里的Patch Conflict章节,按官方建议的顺序打或者先 rollback 冲突补丁。CheckActiveFilesAndExecutables在 Windows 上尤其关键,它检查补丁要替换的 dll/exe 是否被进程占用——Oracle 服务没停干净时,这一步就会报Active files and executables失败。

参数说明:-phBaseDir指向补丁解压目录(含etc和files子目录的那一层),不是files目录本身;-oh在单 home 机器上可省略,但多 home 环境建议始终显式带上,避免读错 inventory。prereq 检查全部通过再进下一步,任何一项 failed 都先解决再 apply。

3. 停库停服务与 apply:Windows 下文件占用的处理顺序

Windows 和 Linux 打补丁最大的差别在于“文件锁”。Linux 上停库后文件句柄基本释放,Windows 上即使shutdown immediate完成,Oracle 的 Windows 服务(OracleService<SID>、OracleOraDB12Home1TNSListener等)仍可能持有 dll,导致 Opatch 替换文件失败。所以 Windows 下的正确顺序是:先停监听、再停数据库、再停服务,最后确认没有oracle.exe残留进程,才执行 apply。

3.1 停库与停服务的完整顺序

很多人只执行shutdown immediate就去 apply,结果卡在CheckActiveFilesAndExecutables。血泪经验是:Windows 服务不停,文件锁不会释放。下面这套顺序我一般固定走一遍。

:: 1. 以 sysdba 登录并停库(先停监听再停库更稳) lsnrctl stop sqlplus / as sysdba SQL> shutdown immediate; SQL> exit; :: 2. 停 Oracle 相关 Windows 服务(服务名按实际实例调整) net stop OracleServiceORCL net stop OracleOraDB12Home1TNSListener :: 3. 确认没有残留 oracle 进程 tasklist | findstr /i "oracle.exe"

逻辑说明:lsnrctl stop先停监听,避免停库过程中还有连接进来。shutdown immediate回滚未提交事务并断开所有会话,比shutdown abort安全,补丁场景下除非库卡死否则不用 abort。net stop停服务是 Windows 特有的关键步骤,服务不停,oracle.exe进程可能仍在后台持有文件句柄。tasklist | findstr用来兜底确认,如果还有输出,说明有进程没退干净,需要taskkill /f /pid <pid>强制结束(谨慎使用,确认是 Oracle 进程再杀)。

参数说明:服务名不是固定的OracleServiceORCL,用sc query state= all | findstr /i oracle可以列出本机所有 Oracle 服务,按实际 SID 替换。taskkill /f是强制终止,只在确认进程无响应时用,正常停服务后不应有残留。

3.2 opatch apply 执行与日志判读

服务停干净、prereq 全过之后,apply 本身反而简单。关键是看日志——Opatch 的失败信息有时很误导,真正的错误在%ORACLE_HOME%\cfgtoollogs\opatch下的日志里。

:: 进入补丁目录执行 apply,-verbose 输出详细过程 cd /d D:\patch\p32876319_122010_MSWIN-x86-64 opatch apply -oh %ORACLE_HOME% -verbose :: 如果补丁需要额外参数(如 online 模式),按 README 加 -online :: opatch apply -oh %ORACLE_HOME% -online

逻辑说明:-verbose会把每个文件的替换过程打出来,失败时能定位到具体文件。apply 成功会输出OPatch succeeded.,失败则输出OPatch failed with error code <n>。error code 常见含义:73多为 prereq 未过或文件占用,135多为 inventory 读取失败(权限或 home 不对),239多为补丁冲突。日志路径%ORACLE_HOME%\cfgtoollogs\opatch\opatch<时间戳>.log,失败后第一件事是翻这个日志的ERROR行,而不是看屏幕上的最后一行。

参数说明:-oh指定 home;-verbose建议始终加,日志更全;-online用于 online patch(部分 12c 补丁支持不停库打),但 Windows 下 online patch 限制多,单实例一般还是走停库流程更稳。apply 完成后不要立刻起库,先跑opatch lspatches确认补丁已登记,再按补丁 README 要求执行datapatch(如果有 SQL 变更)。

3.3 datapatch 与补丁后 SQL 变更

12c 的很多补丁包含 SQL 层面的变更(比如数据字典更新),apply 只替换了二进制文件,SQL 部分要靠datapatch应用。漏掉这一步,库起来后可能报ORA-04063或组件版本不一致。

:: 起库到 mount 或 open 状态后执行 datapatch sqlplus / as sysdba SQL> startup SQL> exit; cd /d %ORACLE_HOME%\OPatch datapatch -verbose

逻辑说明:datapatch读取补丁里的 SQL 脚本并应用到数据库,-verbose输出每个脚本的执行结果。执行完会提示Patch 32876319 successfully applied之类的信息。如果 datapatch 报错,日志在%ORACLE_HOME%\cfgtoollogs\sqlpatch下,常见失败是库没起全或者_SYSTEM_TRIG_ENABLED被关掉。

参数说明:datapatch必须在数据库 open 状态下跑(mount 状态部分脚本无法执行);-verbose用于排错,正常批量维护可省略。跑完用dba_registry_sqlpatch视图核对:

SELECT patch_id, action, status, action_time FROM dba_registry_sqlpatch ORDER BY action_time DESC;

status为SUCCESS才算真正打完,action为APPLY或ROLLBACK对应操作类型。

4. 避坑与排查:五条 Windows 补丁翻车记录

4.1 现象:apply 报 CheckActiveFilesAndExecutables 失败

原因:Oracle 服务没停,或停了服务但oracle.exe残留进程仍持有 dll。Windows 下服务停止和进程退出之间有时间差,尤其监听服务。 解决:按 3.1 的顺序停监听、停库、停服务,tasklist | findstr oracle.exe确认无残留后再 apply。如果仍有残留,用taskkill /f /pid结束,等几秒再重试。

4.2 现象:opatch lspatches 报 Unable to read inventory

原因:当前 shell 不是管理员权限,或ORACLE_HOME指向了不存在的路径,或 inventory 文件被另一个进程锁住。 解决:以管理员身份重开 cmd,echo %ORACLE_HOME%确认路径存在且是目标 home;检查%ORACLE_HOME%\inventory\ContentsXML\inventory.xml是否可读。多实例机器上尤其注意别在错误的 home 下操作。

4.3 现象:apply 成功但 dba_registry_sqlpatch 查不到记录

原因:漏跑datapatch,或者 datapatch 执行时库没 open 全。 解决:确认库已startup到 open,再跑datapatch -verbose,看sqlpatch日志有无报错。补丁的 SQL 变更没应用,二进制和字典版本会对不上。

4.4 现象:补丁冲突,apply 报 error code 239

原因:目标补丁与已装补丁有文件级重叠,通常是前置补丁顺序不对或跳过了某个 RU。 解决:看opatch prereq CheckConflictAgainstOHWithDetail的输出,按补丁 README 的冲突矩阵处理——要么先 rollback 冲突补丁,要么按官方推荐顺序先打前置补丁。别硬 apply。

4.5 现象:rollback 后库起不来,报 ORA-00600

原因:rollback 只回退了二进制,SQL 变更没回退,或者 rollback 顺序与 apply 相反导致字典不一致。 解决:rollback 同样要跑datapatch(它会识别回退的 SQL),并且严格按“后打的先回退”顺序。回退前做一次完整备份,别在没备份的库上试 rollback。

5. 验证与回退:把补丁状态变成可核对的事实

补丁打完不算完,能不能在出问题时快速回退,才是 Windows 环境下真正值钱的能力。我一般固定做三件事:核对dba_registry_sqlpatch、核对opatch lspatches、留一份回退脚本。三者对得上,才算这次补丁闭环。

先看数据库侧的补丁登记,这是最权威的“补丁是否生效”证据:

-- 查 SQL 补丁应用记录,确认 status 为 SUCCESS SELECT patch_id, patch_type, action, status, description, action_time FROM dba_registry_sqlpatch ORDER BY action_time DESC; -- 查组件版本,确认没有 INVALID 组件 SELECT comp_id, version, status FROM dba_registry WHERE status <> 'VALID';

逻辑说明:第一条查补丁应用历史,action=APPLY且status=SUCCESS是目标状态;如果同一 patch_id 有多条记录,看最新一条。第二条查组件有效性,补丁后如果有组件变INVALID,说明 datapatch 没跑全或 SQL 执行失败,需要回看sqlpatch日志。参数上没什么可调的,视图本身只读,注意用 sysdba 或有SELECT_CATALOG_ROLE的账号查。

再看文件侧,opatch lspatches的输出应该和数据库侧对得上:

cd /d %ORACLE_HOME%\OPatch opatch lspatches

如果数据库侧有记录但lspatches没有,说明二进制没替换成功(可能 apply 中途失败但没注意);反过来lspatches有而数据库侧没有,基本就是漏了datapatch。两边对不上时,以dba_registry_sqlpatch为准判断 SQL 层,以lspatches判断文件层,分别补。

回退这件事,我的习惯是 apply 成功后立刻把回退命令写进一个rollback_<patchid>.txt放在补丁目录旁边,内容包括opatch rollback -id <patchid>和随后的datapatch -verbose。真到要回退时,顺序是:停服务 →opatch rollback -id <patchid> -oh %ORACLE_HOME%→ 起库 →datapatch -verbose→ 再查dba_registry_sqlpatch确认action=ROLLBACK且status=SUCCESS。回退前一定做一次冷备,Windows 下文件锁和进程残留会让回退比 apply 更容易卡住,有备份才有后悔药。

还有一个容易被忽略的验证点:补丁后跑一遍utlrp.sql编译无效对象,再查dba_objects里status='INVALID'的数量。补丁带来的字典变更可能让部分存储过程失效,不编译的话业务侧报ORA-04068时你还以为是补丁本身的问题。从那以后我每次打完补丁,都会把dba_registry_sqlpatch、opatch lspatches、无效对象数量这三项强制走一遍,三项都对上才敢跟业务说“可以了”。希望这套顺序帮到你,少在文件锁和漏跑 datapatch 上翻车。

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

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

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

立即咨询