代码改变世界

Oracle 数据库启停脚本:适用于开发测试环境

2026-10-02 07:00  AlfredZhao  阅读(51)  评论(0)    收藏  举报

在开发测试环境中,Oracle 启动和关闭往往要分别敲 lsnrctl 和 sqlplus 命令,步骤多、容易漏,对开发人员也不友好。因为开发测试环境比较简单,启停库通常不会遇到啥异常,所以可以直接把监听器和数据库实例的启停逻辑收进一个脚本,再用两个小包装脚本分别对应启动和停止,操作起来更省心。

01 | 主脚本 db.sh 的结构

脚本放在 /home/oracle/scripts/db.sh,针对的实例是 ORCLCDB。使用前需赋予可执行权限:chmod +x /home/oracle/scripts/db.sh(包装脚本同理)。开头先明确环境变量,避免依赖登录时的默认配置:

export ORACLE_SID=ORCLCDB
export ORACLE_BASE=/opt/oracle
export ORACLE_HOME=/opt/oracle/product/26ai/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export NLS_LANG=american_america.utf8

接着检查执行身份,只有 oracle 用户才能继续,否则直接报错退出。这样能减少用错用户的情况;但以 sqlplus / as sysdba 连接还需该用户具备相应 OS 组权限(如 dba)或已配置认证,否则仍会连接失败。

02 | 启动与停止的顺序

脚本用 case 接收参数,分三种操作。

start 时先启动监听器,再启动数据库。需要注意:脚本未检查 lsnrctl start 和 startup 的返回状态,若其中任一步失败仍会打印“启动完成”,生产环境建议在关键步骤后增加返回码判断或人工确认输出:

lsnrctl start
sqlplus -s / as sysdba <<EOF
startup;
exit;
EOF

stop 时顺序相反,先关数据库再停监听:

sqlplus -s / as sysdba <<EOF
shutdown immediate;
exit;
EOF
lsnrctl stop

关闭用 shutdown immediate,它会回滚未提交事务并断开所有已连接会话,适合常规维护停机;对在线业务执行前应确认无关键事务进行中。启动和停止都通过 sqlplus -s / as sysdba 以静默方式执行,输出更干净。

启动与停止的操作顺序可以用下面的流程图概括:

flowchart TD A[执行 db.sh] --> B{参数判断} B -->|start| C[启动监听器 lsnrctl start] C --> D[启动数据库 startup] D --> E[启动完成] B -->|stop| F[关闭数据库 shutdown immediate] F --> G[停止监听器 lsnrctl stop] G --> H[关闭完成] B -->|status| I[检查 PMON 进程] I --> J[查询 v$instance 状态] J --> K[查看监听器状态] B -->|其他| L[提示用法并退出]

03 | status 检查三项状态

status 参数用于快速体检,依次看三件事。注意:实例未启动时,查询 v$instance 会报 ORA-01034 等错误,属预期现象,可结合 PMON 进程检查判断:

  • PMON 进程:ps -ef | grep [p]mon_$ORACLE_SID
  • 实例状态:查询 v$instance 的 status 字段
  • 监听器状态:lsnrctl status 中过滤 Status 和 Services Summary

三块信息拼在一起,能大致判断实例和监听是否正常。

04 | 两个包装脚本

为了少敲参数,笔者另外写了两个小脚本。start_db.sh 先定位自身所在目录,再调用主脚本的 start:

SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
exec "${SCRIPT_DIR}/db.sh" start

stop_db.sh 同理,只是把参数换成 stop。用 exec 替换当前进程,脚本路径通过 dirname 动态获取,因此只要 db.sh 与包装脚本位于同一目录即可调用;但 db.sh 内的 ORACLE_HOME 等路径为硬编码,迁移到其他环境时需相应修改。

如果参数不对,主脚本会提示用法:/home/oracle/scripts/db.sh {start|stop|status}。

05 | 原始完整脚本

为方便大家直接参考和取用,下面附上三个脚本的原始完整内容。只需要修改下Oracle环境变量。

db.sh

#!/bin/bash
# =================================================================
# Oracle Database & Listener Control Script
# Script Path: /home/oracle/scripts/db.sh
# ORACLE_SID: ORCLCDB
# =================================================================

# 1. 明确 Oracle 环境变量(根据实际情况修改变量值)
export ORACLE_SID=ORCLCDB
export ORACLE_BASE=/opt/oracle
export ORACLE_HOME=/opt/oracle/product/26ai/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export NLS_LANG=american_america.utf8

# 2. 检查用户身份
if [ "$(whoami)" != "oracle" ]; then
    echo "错误: 请使用 oracle 用户执行此脚本。"
    exit 1
fi

# 3. 操作分发
case "$1" in
    start)
        echo "--------------------------------------------------"
        echo "[1/2] 正在启动 Oracle 监听器..."
        lsnrctl start
        
        echo ""
        echo "[2/2] 正在启动 Oracle 数据库 ($ORACLE_SID)..."
        sqlplus -s / as sysdba <<EOF
startup;
exit;
EOF
        echo "--> 数据库及监听启动完成。"
        echo "--------------------------------------------------"
        ;;
        
    stop)
        echo "--------------------------------------------------"
        echo "[1/2] 正在关闭 Oracle 数据库 ($ORACLE_SID)..."
        sqlplus -s / as sysdba <<EOF
shutdown immediate;
exit;
EOF

        echo ""
        echo "[2/2] 正在停止 Oracle 监听器..."
        lsnrctl stop
        echo "--> 数据库及监听已安全关闭。"
        echo "--------------------------------------------------"
        ;;
        
    status)
        echo "--------------------------------------------------"
        echo "【1. PMON 进程检查】"
        ps -ef | grep [p]mon_$ORACLE_SID
        
        echo ""
        echo "【2. 数据库实例状态】"
        sqlplus -s / as sysdba <<EOF
set heading off
select 'Instance Status: ' || status from v\$instance;
exit;
EOF
        
        echo ""
        echo "【3. 监听器状态简报】"
        lsnrctl status | grep -E "(Status|Services Summary)" -A 5
        echo "--------------------------------------------------"
        ;;
        
    *)
        echo "用法: /home/oracle/scripts/db.sh {start|stop|status}"
        exit 1
        ;;
esac

start_db.sh

#!/bin/bash
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
exec "${SCRIPT_DIR}/db.sh" start

stop_db.sh

#!/bin/bash
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
exec "${SCRIPT_DIR}/db.sh" stop

关注我,和AI一起成长~