重庆思庄Oracle、KingBase、PostgreSQL、Redhat认证学习论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 763|回复: 0
打印 上一主题 下一主题

[补丁] Oracle Database 19c单实例自动补丁更新脚本(RU+OJVM)

[复制链接]
跳转到指定楼层
楼主
发表于 2025-7-25 22:07:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#!/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


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 支持支持 反对反对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|重庆思庄Oracle、Redhat认证学习论坛 ( 渝ICP备12004239号-4 )

GMT+8, 2026-4-17 22:47 , Processed in 0.229181 second(s), 20 queries .

重庆思庄学习中心论坛-重庆思庄科技有限公司论坛

© 2001-2020

快速回复 返回顶部 返回列表