重庆思庄Oracle、KingBase、PostgreSQL、Redhat认证学习论坛
标题:
Oracle Database 19c单实例自动补丁更新脚本(RU+OJVM)
[打印本页]
作者:
ZhangQi
时间:
2025-7-25 22:07
标题:
Oracle Database 19c单实例自动补丁更新脚本(RU+OJVM)
#!/bin/bash
# 名称:oracle_19c_ru_ojvm_upgrade.sh
# 描述:Oracle 19c RU+OJVM 一键升级脚本(通用版 19.3~19.28)
# 用法:直接运行,无需传参,脚本将提示输入目标 RU 版本
# 要求:以oracle用户执行,需提前下载补丁文件
# =============== 安全控制 ===============
set -euo pipefail
trap 'echo "ERROR: 脚本异常退出,请检查日志!"; exit 1' ERR
### ================ 配置区(请按需修改) ================
ORACLE_SID="orcl"
ORACLE_HOME="/u01/app/oracle/product/19c/dbhome_1"
PATCH_DIR="/patches/19.19" #补丁包所在路径
RU_PATCH="p35042068_190000_Linux-x86-64.zip" # RU补丁号示例
OJVM_PATCH="p35050341_190000_Linux-x86-64.zip" # OJVM补丁号示例
ROLLBACK_FILE="/backup/rollback_${ORACLE_SID}_$(date +%Y%m%d).sql"
### ================ RU→OPatch 映射 ================
declare -A MAP_OPATCH=(
["19.3"]="12.2.0.1.17" ["19.4"]="12.2.0.1.17" ["19.5"]="12.2.0.1.17" ["19.6"]="12.2.0.1.17"
["19.7"]="12.2.0.1.19" ["19.8"]="12.2.0.1.19" ["19.9"]="12.2.0.1.19"
["19.10"]="12.2.0.1.23" ["19.11"]="12.2.0.1.23"
["19.12"]="12.2.0.1.25" ["19.13"]="12.2.0.1.27" ["19.14"]="12.2.0.1.28" ["19.15"]="12.2.0.1.29"
["19.16"]="12.2.0.1.30" ["19.17"]="12.2.0.1.32" ["19.18"]="12.2.0.1.34" ["19.19"]="12.2.0.1.36"
["19.20"]="12.2.0.1.37" ["19.21"]="12.2.0.1.37" ["19.22"]="12.2.0.1.40"
["19.23"]="12.2.0.1.41" ["19.24"]="12.2.0.1.42" ["19.25"]="12.2.0.1.43"
["19.26"]="12.2.0.1.44" ["19.27"]="12.2.0.1.45" ["19.28"]="12.2.0.1.46"
)
### ================ 版本号比较函数(语义比较) ================
vercomp() {
local IFS=.
local i
local -a a=($1) b=($2)
local max=${#a[@]}
(( ${#b[@]} > max )) && max=${#b[@]}
for ((i=0; i<max; i++)); do
(( ${a:-0} > ${b:-0} )) && return 0
(( ${a:-0} < ${b:-0} )) && return 1
done
return 0
}
### ================ 预检函数 ====================
precheck() {
echo ">>> 开始预检..."
# 1.用户检查
if [ "$(whoami)" != "oracle" ]; then
echo "错误:必须使用oracle用户执行!"
exit 1
fi
# 2.RU 版本检查
CUR_RU_FULL=$(sqlplus -s / as sysdba <<'EOF'
set heading off feedback off pagesize 0
SELECT version_full FROM v$instance;
exit
EOF
)
CUR_RU=$(echo "$CUR_RU_FULL" | awk -F. '{print $1 "." $2}')
echo "当前数据库 RU = $CUR_RU,目标 RU = $TARGET_RU"
if vercomp "$CUR_RU" "$TARGET_RU"; then
echo "INFO:当前 RU 已 ≥ 目标 RU,无需升级"; exit 0
fi
# 3.补丁文件检查
if [[ ! -f "${PATCH_DIR}/${RU_PATCH}" || ! -f "${PATCH_DIR}/${OJVM_PATCH}" ]]; then
echo "ERROR:补丁文件缺失!请检查 ${PATCH_DIR} 下是否存在 $RU_PATCH 和 $OJVM_PATCH"; exit 1
fi
# 4. 数据库状态检查
DB_STATUS=$(sqlplus -s / as sysdba <<'EOF'
set heading off feedback off pagesize 0
select status from v$instance;
exit
EOF
)
if [ "$DB_STATUS" != "OPEN" ]; then
echo "错误:数据库未处于OPEN状态!"
exit 1
fi
# 5.OPatch 版本检查
echo ">>> 检查OPatch版本"
CUR_OPATCH=$("$ORACLE_HOME/OPatch/opatch" version | awk '/OPatch Version:/ {print $NF}')
echo "当前 OPatch = $CUR_OPATCH,目标 ≥ $REQ_OPATCH"
if [[ ! "$CUR_OPATCH" =~ ^12\.2\.0\.1\.[0-9]+$ ]]; then
echo "ERROR:OPatch 格式不对:$CUR_OPATCH"; exit 1
fi
IFS='.' read -r _ _ _ _ CUR_N <<<"$CUR_OPATCH"
IFS='.' read -r _ _ _ _ REQ_N <<<"$REQ_OPATCH"
if (( CUR_N < REQ_N )); then
echo "ERROR:OPatch ($CUR_OPATCH) 低于目标 RU($TARGET_RU) 要求 ($REQ_OPATCH)"; exit 1
fi
echo "预检通过"
}
### ================ 备份函数 ====================
create_backup() {
echo ">>> 创建回滚点..."
sqlplus -s / as sysdba <<EOF >"$ROLLBACK_FILE"
set serveroutput on
exec dbms_qopatch.get_sqlpatch_status;
exit;
EOF
echo ">>> 备份 OPatch 列表..."
"$ORACLE_HOME/OPatch/opatch" lsinventory -detail >"${PATCH_DIR}/inventory_bak_$(date +%s).txt"
}
### ================ 应用补丁函数 ====================
apply_patch() {
local patch_file=$1
local patch_type=$2
echo ">>>>>> 开始应用 ${patch_type} 补丁 <<<<<<"
# 阶段1: 准备环境
echo "=== 阶段1: 准备环境 ==="
if [ ! -f "${PATCH_DIR}/$patch_file" ]; then
echo "错误:补丁文件 ${PATCH_DIR}/$patch_file 不存在!"
exit 1
fi
echo "解压补丁文件: $patch_file"
unzip -o "${PATCH_DIR}/$patch_file" -d "${PATCH_DIR}"
PATCH_NUMBER=$(echo "$patch_file" | grep -oP 'p\K\d+')
PATCH_DIR_FULL="${PATCH_DIR}/${PATCH_NUMBER}"
if [ ! -d "$PATCH_DIR_FULL" ]; then
echo "错误:解压后的补丁目录 $PATCH_DIR_FULL 不存在!"
echo "解压后的内容:"
ls -l "${PATCH_DIR}"
exit 1
fi
# 阶段2: 应用补丁
echo "=== 阶段2: 应用补丁 ==="
echo "停止Oracle服务..."
sqlplus / as sysdba <<EOF
shutdown immediate
exit
EOF
lsnrctl stop
echo "应用补丁到ORACLE_HOME..."
cd "$PATCH_DIR_FULL"
$ORACLE_HOME/OPatch/opatch apply -silent
# 阶段3: 后处理
echo "=== 阶段3: 后处理 ==="
echo "启动数据库到正常模式..."
sqlplus / as sysdba <<EOF
startup
exit
EOF
echo "执行datapatch更新数据库字典..."
cd $ORACLE_HOME/OPatch
./datapatch -verbose
# 启动监听器
lsnrctl start
echo ">>>>>> ${patch_type} 补丁应用完成 <<<<<<"
echo ""
}
### ================ 主流程 ====================
main() {
read -rp "请输入你要打的补丁版本(如 19.28): " TARGET_RU
REQ_OPATCH="${MAP_OPATCH[$TARGET_RU]:-}"
if [[ -z "$REQ_OPATCH" ]]; then
echo "ERROR:不支持目标 RU=$TARGET_RU,请检查映射表!"; exit 1
fi
export TARGET_RU # 显式导出,确保所有函数中都能访问这个变量
precheck # 执行预检
create_backup # 创建备份
apply_patch "$RU_PATCH" "RU" # 应用RU补丁
apply_patch "$OJVM_PATCH" "OJVM" # 应用OJVM补丁
# 最终验证
echo ">>> 校验已应用补丁列表:"
"$ORACLE_HOME/OPatch/opatch" lspatches
echo ">>>>>> 升级成功!请执行健康检查脚本验证数据库状态。"
}
# 执行主函数
main | tee /tmp/patch_${ORACLE_SID}_$(date +%Y%m%d).log
欢迎光临 重庆思庄Oracle、KingBase、PostgreSQL、Redhat认证学习论坛 (http://bbs.cqsztech.com/)
Powered by Discuz! X3.2