ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Windows上Oracle 12c打补丁:Opatch命令详解与避坑指南

Windows上Oracle 12c打补丁:Opatch命令详解与避坑指南 简介针对Windows平台的Oracle 12c补丁工具OPatch资源包面向数据库管理员与系统运维人员解决Windows环境下应用Oracle补丁时OPatch工具缺失或版本不匹配的问题涵盖补丁检测、安装、回滚等常见维护场景。压缩包共454个文件整体102.88MB以jar、dll、exe等可执行与依赖组件为主辅以bat批处理脚本、properties配置文件、md说明文档及sh辅助脚本构成一套完整可用的OPatch工具链便于在无外网环境离线部署和补丁应用。包内包含核心的opatch命令与配套的补丁应用、数据补丁、自动补丁等工具以及JVM发现、WebLogic补丁等辅助脚本并附有证书、黑名单、字体等环境配置文件可帮助读者快速了解Oracle补丁工具的目录结构、运行机制和典型用法提升补丁管理与排错效率。已有996人学习下载适合需要手工维护Oracle 12c补丁的中高级DBA与运维人员参考。1. 在 Windows 上给 Oracle 12c 打补丁为什么 Opatch 才是真正的入口Windows 服务器上的 Oracle 12c 要打补丁很多人第一反应是在解压目录里找 setup.exe双击后却发现什么都没发生。真正干活的是一套命令行工具 Opatch它负责把补丁内容写进 ORACLE_HOME 的二进制文件同时更新 inventory补丁清单少了它补丁包解压得再整齐也白搭。这篇笔记写给两类人一类是刚接手 12c 的 DBA 和运维想知道在 Windows 上打补丁到底有哪些步骤、哪些命令必须先验证另一类是已经打过几次补丁但踩过坑的人比如补丁装完版本没变、文件被占用、回滚失败这类翻车现场。我会按“安装前清单 → apply 与验证 → rollback → 常见坑 → 一键封装”的顺序把它讲透。2. 准备阶段Opatch 版本核对、补丁类型与 Windows 专属环境要求2.1 先分清 12c 的补丁家族CPU、PSU 和 RU 在 Windows 上的叫法Oracle 12c 的补丁体系对新手相当不友好因为同样叫“打补丁”三个月一次的和临时补的安装方式完全不同。常见的有 CPUCritical Patch Update每季度发布主要修安全漏洞会被后续补丁覆盖PSUPatch Set Update是累积性的通常含上一个季度的 CPU在 12.1 时代最常见从 12.2 开始季度补丁更多以 RURelease Update和 RURRelease Update Revision命名。有一点要记住这些补丁在 Windows 平台上不能跨平台混用DB 和 GIGrid Infrastructure要分别有对应的补丁包任意拿 Linux 的文件往 Windows 的 ORACLE_HOME 里覆盖系统直接起不来。下载下来的补丁包文件名一般长这样p8位补丁号_版本_MSW-x86-64.zip。中间的MSW-x86-64就是 Microsoft Windows 平台标记对应 Linux 平台的Linux-x86-64下载时一定要看准。解压后会得到一个同名目录里面有 README.html、etc 目录和一堆文件。README.html 是三个必读项最低 Opatch 版本、数据库版本要求12.1.0.2 还是 12.2.0.1、是否需要额外执行 SQL 脚本。网上的很多 oracle12c 安装教程在打补丁这一步都草草带过实际补丁包的规范远比安装时复杂前置条件漏一条就可能白等一个维护窗口。2.2 确认 Opatch 版本版本不对补丁装了等于白装补丁包的 README 里都会写“最低 Oracle Opatch 版本 12.2.0.1.x”之类的硬性要求。如果本机 Opatch 太老apply 会在前置检查阶段直接失败报类似于 OUI 权限不足或版本太旧的错误根本走不到文件替换那一步。在 Windows 上确认版本的方法很简单用管理员身份打开 cmd然后执行set ORACLE_HOMED:\app\oracle\product\12.1.0.2\dbhome_1 cd /d %ORACLE_HOME%\OPatch opatch.bat version opatch.bat lsinventory第一行是手动指定 ORACLE_HOME避免登录用户的环境变量指向别的数据库目录cd /d跨盘符进入 OPatch 目录保证调用的批处理是当前目录里的这一份version会输出当前 Opatch 的版本号lsinventory会列出这个 ORACLE_HOME 下已经安装的全部补丁这一步的输出在后续 analyze 和 rollback 时都要用它来对照。在 Windows 上执行时确认 cmd 窗口标题带“管理员”字样否则后面 apply 会遇到大量权限类报错白折腾半小时。如果服务器上装过多个 Oracle 产品PATH 环境变量里可能残留着多个 OPatch 路径最省心的做法是把完整路径写进命令也就是始终用%ORACLE_HOME%\OPatch\opatch.bat而不是裸敲opatch。另外建议把 ORACLE_HOME 写进系统环境变量不写也行但脚本化时会麻烦。这里我一般会在执行前顺手敲一句where opatch看看系统到底把命令解析到了哪个目录如果指向的不是当前 ORACLE_HOME后面一定出幺蛾子。2.3 Windows 与 Linux 打补丁的差异服务、文件锁和权限同样的补丁包Windows 和 Linux 的安装逻辑完全不一样。Linux 上可以拿 oracle 用户直接跑$ORACLE_HOME/OPatch/opatch apply只要数据库是干净的大多数补丁甚至可以在线完成Windows 上最大的敌人是文件锁。Oracle 的服务进程会把 dll 加载进内存opatch 要覆盖它时就会被系统拒绝报“文件被另一个进程占用”。所以标准做法是打补丁前先把对应的服务停掉。对比点Linux 环境Windows 环境执行用户oracle 系统用户管理员 cmd是否需要停服务多数补丁不需要建议停 OracleService 和 Listener常见被占用文件少量 so 文件dll、exe 被服务加载后拒绝覆盖Opatch 调用方式$ORACLE_HOME/OPatch/opatch%ORACLE_HOME%\OPatch\opatch.bat补丁平台目录Linux-x86-64MSW-x86-64在 Windows 上打补丁失败的高频原因就是OracleServiceORACLE_SID这个服务还在运行。opatch 不是简单的文件复制它会调系统 API 替换 dll一旦服务占用就会中断。所以把数据库服务和监听服务停掉再 apply是 Windows 上更省心的姿势哪怕补丁说明写着支持在线。还有一个老坑解压路径不要放在中文目录或带空格的路径里比如D:\数据库补丁内部脚本对路径解析特别脆弱放在D:\patch\这种短路径最省心。环境变量和 PATH 配置是 Windows 上最常见的翻车点之一数据库、JDK、中间件多产品共存的机器尤其要小心 PATH 里残留的旧 Opatch 路径。3. 在 Windows 上执行 Opatch apply从补丁解压到验证的全流程3.1 下载、解压与 README.html 的三项必读信息补丁包从官方支持网站下载后先用解压工具放到短路径。Windows 10 和 Windows Server 2019 自带 tar 命令可以直接解压 zip老系统用 PowerShell 的 Expand-Archive 或 7-Zip 都行cd /d D:\patch tar -xf p12345678_121020_MSW-x86-64.zip解压后的目录名和 zip 一致比如p12345678_121020。进入目录后用浏览器打开 README.html重点找一个章节叫 Pre-Installation Instructions里面会写三类信息最低 Opatch 版本、数据库版本要求比如仅适用于 12.1.0.2.0、是否需要额外执行 SQL 脚本。第二类信息特别容易漏因为有些补丁只改二进制有些还要在数据库里跑 catupgrd 之类的数据字典升级脚本是否执行直接决定数据库起不起得来。README.html 里如果写了 “Make sure the Oracle service is stopped”那就老老实实停服务别讨价还价。3.2 冲突分析opatch apply -analyze必须在正式 apply 前跑直接 apply 报冲突再回滚会浪费大量时间更糟糕的是可能把一个本来健康的数据库打成“半补丁”状态。Opatch 提供了 analyze 模式只做检查不写文件相当于正式操作前的预检。这一步我无论多急都会做因为它能挡住绝大多数依赖冲突cd /d %ORACLE_HOME%\OPatch opatch.bat apply -analyze -oh %ORACLE_HOME% -ph D:\patch\p12345678_121020 echo %ERRORLEVEL%-oh指定 ORACLE_HOME-ph指定补丁目录两者都必须是绝对路径。analyze 会检查补丁与已应用补丁的冲突、补丁与二进制版本的兼容性、以及补丁内部文件是否完整。返回码为 0 表示通过非 0 就停在前面输出的冲突信息里比如它会直接告诉你“Patch xxx conflicts with patch yyy”。如果想看更细的依赖报告我一般还会加一句opatch.bat prereq CheckConflictAgainstOHWithDetail -ph D:\patch\p12345678_121020这条会把每个文件层面的依赖都列出来。analyze 不是百分百保证 apply 一定成功文件锁、磁盘空间这类运行时问题它管不着但它能筛掉九成以上的“装完起不来”。3.3 正式 apply命令与执行背后的动作analyze 通过后就可以正式应用了。在 Windows 上我习惯先把服务和监听停掉再进入 Opatch 目录执行net stop OracleServiceORCL nul 21 net stop OracleOraDB12Home1TNSListener nul 21 cd /d %ORACLE_HOME%\OPatch opatch.bat apply -oh %ORACLE_HOME% -ph D:\patch\p12345678_121020net stop后面的服务名不固定可以用sc query | findstr /i oracle查实际服务名。apply 命令会做这么几件事读取补丁目录里的配置文件、备份当前二进制到 ORACLE_HOME 下的.patch_storage目录、替换 dll 和 exe 文件、更新 SQL 脚本目录、最后把补丁信息写进 inventory。整个过程中终端会打印一行行进度最后到 100%。Windows 上有两个点需要特别提醒一是不要看它长时间没输出就 CtrlC卡住时先看日志%ORACLE_HOME%\cfgtoollogs\opatch\下最新的 log 文件再决定是否干预二是 apply 完成后一般不会自动启动数据库需要手动启动并按 README 要求执行对应的 SQL 脚本。脚本名因补丁而异必须按 README.html 里的说明来猜一个名字跑反而会出问题。3.4 验证lsinventory 与日志交叉确认apply 输出 100% 并不代表万事大吉。验证要分两层第一层是确认 inventory 里出现了这个补丁第二层是确认数据库层也生效了。第一层用这条命令cd /d %ORACLE_HOME%\OPatch opatch.bat lsinventory -bugs_fixed | findstr 12345678lsinventory会列出当前 ORACLE_HOME 下所有已应用补丁加-bugs_fixed会在每个补丁下方显示它修复的 bug 列表用findstr过滤刚才的补丁号能搜到就说明 inventory 记录已经写入。但仅凭这条还不够因为 Windows 上有过“文件复制成功但数据库进程加载的还是旧版本”的情况所以第二层验证要启动数据库后执行一句 SQLselect * from registry$history;看补丁记录和安装时间是否对得上。如果这里能看到补丁 ID且数据库版本视图v$version与补丁说明一致才算真正打上了。日志文件也不要急着删cfgtoollogs\opatch\里保留了 apply 的完整过程出问题时要靠它判断卡在哪一步。4. 回滚与补丁清理Windows 上的后悔药要按这套流程吃4.1 回滚前必须满足的三个条件打补丁没有后悔药Opatch 虽然提供了 rollback 命令但也不是无条件可用的。回滚前必须确认三件事第一能拿到当初应用补丁时的 patch id 和确切版本最好的来源是opatch lsinventory的输出在打补丁当天就应该顺手存一份文本第二有可靠的备份Windows 上最简单的方式是打补丁前对 ORACLE_HOME 做一次文件级副本或整机快照不要只依赖 opatch 自己备份到.patch_storage的那份第三数据库实例和监听服务必须处于停止状态否则 rollback 时同样会遇到文件占用。这三条缺一条回滚就可能从“后悔药”变成“二次事故”。回滚前再看一遍补丁包 README.html 的 Rollback Instructions有的补丁要求回滚后重新启动实例执行更新脚本有的要求回滚后不执行任何 SQL 直接启动差别很大。4.2 rollback 命令按 patch id 精准撤销回滚用opatch rollback参数比 apply 更简单因为它只需要补丁 ID不需要补丁目录。操作前先停服务net stop OracleServiceORCL nul 21 net stop OracleOraDB12Home1TNSListener nul 21 cd /d %ORACLE_HOME%\OPatch opatch.bat rollback -id 12345678 -oh %ORACLE_HOME%-id后面跟的是当初 apply 的补丁号可以在opatch lsinventory里查到注意不要带p前缀也不带路径。rollback 前同样可以先加一个-analyze参数试跑opatch.bat rollback -analyze -id 12345678 -oh %ORACLE_HOME%它会先检查当前系统中是否有其他补丁依赖这个补丁如果有依赖会提示冲突。rollback 的执行过程和 apply 相反它会从.patch_storage目录里找旧文件覆盖回去再更新 inventory。如果 rollback 时报“Patch 12345678 is not applied”说明当初 apply 时 inventory 就没写成功先查日志确认补丁是否真的在系统里再决定是重新 apply 还是直接恢复备份。4.3 清理日志与临时空间别让 C 盘静悄悄爆掉Oracle 的 Opatch 日志默认写在%ORACLE_HOME%\cfgtoollogs\opatch\命名格式是opatch_时间戳.log每次 apply、rollback、analyze 都会生成新文件。一两个补丁看不出问题打上三五年这个目录轻轻松松积累几个 GB。验证无误后我一般会把 30 天前的日志压缩归档到别的盘再删掉解压出来的补丁目录forfiles /p %ORACLE_HOME%\cfgtoollogs\opatch /s /m *.log /d -30 /c cmd /c del pathforfiles是 Windows 自带命令/d -30表示只处理 30 天以前的文件/m *.log匹配日志文件/s处理子目录。另外还要检查%TEMP%和用户AppData\Local\Temp下有没有 Opatch 留下的临时文件apply 过程中如果异常中断这里容易残留几百 MB 的数据。清理时不要手动去删 ORACLE_HOME 下的文件尤其是.patch_storage目录那里面保存着所有历史补丁的备份手动删掉会让以后所有 rollback 都失效。日志可以删补丁目录可以删.patch_storage坚决不碰。5. Windows 下 Opatch 的避坑指南5 条血泪记录5.1 apply 时报“文件被占用”或“拒绝访问”现象opatch apply 执行到一半终端弹红字提示某个 dll 无法访问后面跟着“being used by another process”。原因OracleService 服务还在运行目标文件已经被加载到服务进程里或者是 cmd 窗口没有用管理员身份打开。解决先执行net stop OracleServiceORCL和net stop OracleOraDB12Home1TNSListener再以管理员身份重新打开 cmd重跑 analyze 和 apply。如果仍然提示占用打开任务管理器检查是否有残留的 oracle 进程有就直接结束再重试。5.2 opatch 命令执行后提示找不到补丁目录或版本不对现象同一个命令在 A 机器上跑得好好的在 B 机器上报“cannot find opatch”或识别到的 ORACLE_HOME 完全不对。原因PATH 里第一个命中的 opatch.bat 来自另一个 Oracle 产品目录或者-ph传给了一个带中文的路径。解决不依赖 PATH直接敲%ORACLE_HOME%\OPatch\opatch.bat全路径先跑where opatch看看当前解析到的是哪个目录补丁解压目录统一挪到D:\patch\这种纯英文短路径下再执行。这个坑在装有多个版本数据库的机器上特别容易踩。5.3 apply 长时间卡在 97% 不动日志写着 Updating inventory现象进度停在 97%超过十分钟没有新输出日志最后一行是 “Updating inventory ...”。原因文件替换已经完成但 Windows Defender 或第三方杀毒软件正在扫描刚替换的 dll导致 inventory 更新被临时锁住。解决先等足 15 到 20 分钟观察日志文件大小是否还在增长如果完全停滞在维护窗口内临时关闭实时防护再重试 apply强行结束进程前一定要先看日志确认不是正常慢速执行。遇到这类问题最忌讳手快直接 CtrlC 把 inventory 写到一半补丁状态会变成既不在已应用列表、文件已被替换的灰色地带恢复起来非常痛苦。5.4 apply 显示成功但 lsinventory 里 Opatch 版本还是旧的现象补丁说明要求 Opatch 版本不低于 12.2apply 过程也显示成功但再次查询opatch version还是原来的旧版本。原因你执行的 version 命令来自 PATH 中的另一个 opatch而刚才 apply 用的却是%ORACLE_HOME%\OPatch\opatch.bat也就是说“打补丁和查版本”用的是两套工具自然对不上。解决所有 Opatch 操作统一用完整路径先执行reg query HKLM\SOFTWARE\ORACLE确认系统注册表里的 ORACLE_HOME 指向哪里再把当前要操作的 ORACLE_HOME 放到所有命令的最前面。见过不少运维在打补丁前忘了这一步最后白忙一整晚。5.5 补丁打完后数据库无法启动报 ORA-00600 或无法识别文件现象apply 顺利结束启动数据库时报 ORA-00600 内部错误或者提示某个 dll 版本不受支持。原因二进制替换了一半、数据库服务在 apply 过程中仍在运行导致部分动态库被写入不全、Windows 平台目录选错。解决不要尝试在现有状态下修复直接回滚执行opatch.bat rollback -id 补丁号 -oh %ORACLE_HOME%回滚后再启动数据库如果 rollback 也报错就恢复打补丁前做的 ORACLE_HOME 备份。回滚成功后把补丁包文件名里的平台标记再核对一遍确认不是拿 Linux 版补丁硬打在 Windows 上。6. 进阶技巧用一条批处理把 Opatch 检查、apply、验证串起来手工敲命令虽然稳但每周都要给不同环境打补丁时就嫌烦了。我习惯把整个流程封装成一个批处理脚本入参只有补丁目录剩下的检查、停服务、apply、验证全部交给脚本echo off setlocal set ORACLE_HOMED:\app\oracle\product\12.1.0.2\dbhome_1 set PATCH_DIRD:\patch\p12345678_121020 set OPATCH%ORACLE_HOME%\OPatch\opatch.bat echo [1/5] stop oracle services... net stop OracleServiceORCL nul 21 net stop OracleOraDB12Home1TNSListener nul 21 echo [2/5] check opatch version... call %OPATCH% version echo [3/5] analyze patch... call %OPATCH% apply -analyze -oh %ORACLE_HOME% -ph %PATCH_DIR% if errorlevel 1 goto :fail echo [4/5] apply... call %OPATCH% apply -oh %ORACLE_HOME% -ph %PATCH_DIR% if errorlevel 1 goto :fail echo [5/5] verify... call %OPATCH% lsinventory -bugs_fixed | findstr 12345678 echo done. goto :end :fail echo Opatch failed. check log in %ORACLE_HOME%\cfgtoollogs\opatch\ :end endlocal脚本里的补丁号 12345678 是示例占位实际使用时要把它替换成你下载的补丁 ID同时把PATCH_DIR改成解压后的完整目录。call关键字不能省批处理调用另一个 bat 文件后如果不加 call当前脚本会直接结束不再返回errorlevel是 opatch 自己的返回码analyze 失败会停在 fail 分支。脚本最后一步的 findstr 只是简单的文本匹配真正上线前我还会给脚本加一段“启动数据库后查询 registry$history”的验证逻辑毕竟 inventory 有记录不等于数据库层已经生效。脚本本身没有对中文路径做特殊处理如果服务端 cmd 默认编码是 GBK建议把脚本另存为 ANSI 编码防止注释乱码导致if errorlevel判断失效。我当初在 Windows 上第一次打 12c 补丁时就是跳过了 analyze 直接 apply结果打出一个“文件覆盖失败但 inventory 已记录”的怪状态回滚又花了两小时。从那以后养成的习惯是analyze 必跑、服务必停、验证必须查数据库而不是只看终端输出。这套脚本是我自己压箱底的东西希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进