systemd服务单元文件必须通过environmentfile加载oracle环境变量(如oracle_home、oracle_sid、path等),因systemd不读取shell配置文件;需配合user=oracle、execstart调用dbstart、execstop调用dbshut、remainafterexit=yes及正确设置/etc/oratab权限,才能确保oracle实例安全可靠开机自启与正常停库。

systemd服务单元文件必须定义EnvironmentFile加载Oracle环境变量
Oracle数据库启动依赖完整的环境变量(ORACLE_HOME、ORACLE_SID、PATH等),而systemd默认不读取~/.bash_profile或/etc/profile。直接在ExecStart里写sqlplus / as sysdba @startup.sql会因找不到命令或连不上实例失败。
正确做法是把Oracle环境变量单独抽成文件,比如/etc/sysconfig/oracle-db:
ORACLE_HOME=/u01/app/oracle/product/19c/dbhome_1 ORACLE_SID=orcl PATH=/usr/local/bin:/bin:/usr/bin:/u01/app/oracle/product/19c/dbhome_1/bin LD_LIBRARY_PATH=/u01/app/oracle/product/19c/dbhome_1/lib
然后在service文件中用EnvironmentFile显式加载:
-
EnvironmentFile=/etc/sysconfig/oracle-db必须放在[Service]段,且早于ExecStart - 不要用
Source或ExecStartPre=source ...——systemd不支持shell source语义 - 确保
/etc/sysconfig/oracle-db权限为644,属主为root,否则systemd拒绝读取
ExecStart必须调用dbstart而非直接sqlplus
Oracle官方推荐用$ORACLE_HOME/bin/dbstart启库,它会自动检查$ORACLE_HOME/network/admin/listener.ora、读取/etc/oratab判断是否启动对应实例,并按依赖顺序拉起监听器和数据库。手动用sqlplus硬启容易漏掉监听,导致应用连不上。
对应ExecStart应写成:
ExecStart=/u01/app/oracle/product/19c/dbhome_1/bin/dbstart $ORACLE_HOME
注意两点:
-
dbstart脚本本身需要可执行权限(chmod +x),且其内部硬编码了ORACLE_HOME路径,所以传参必须一致 -
/etc/oratab里对应实例行末尾必须是Y(如orcl:/u01/app/oracle/product/19c/dbhome_1:Y),否则dbstart跳过该实例 - 别用
su - oracle -c "..."——systemd有更干净的用户切换机制(见下一条)
必须用User和Group指定oracle用户,禁用Root直启
Oracle进程不能以root运行,否则数据库报错ORA-01031: insufficient privileges,且监听器无法绑定1521端口(非特权端口除外)。systemd提供原生用户隔离能力,比shell包装更可靠。
- 设置
User=oracle和Group=oinstall(或dba),systemd会自动切换用户并继承其HOME环境 - 确保
oracle用户对$ORACLE_HOME有读+执行权限,对$ORACLE_HOME/dbs有读写权限 - 如果
dbstart内部调用了lsnrctl,还需确认oracle用户能访问$ORACLE_HOME/network/admin - 不要加
PermissionsStartOnly=true——这会让ExecStart以root跑前半段,反而破坏权限上下文
停库必须用dbshut且设Type=oneshot
dbshut是dbstart的配对脚本,负责按反序关闭监听器和数据库。若用kill或sqlplus发shutdown immediate,可能只关了实例,监听器还挂着,下次启库时端口冲突。
关键配置项:
-
Type=oneshot:告诉systemd这个服务没有长期运行的主进程,避免超时误判失败 ExecStop=/u01/app/oracle/product/19c/dbhome_1/bin/dbshut $ORACLE_HOME-
RemainAfterExit=yes:让systemd认为服务“仍存在”即使没进程,方便systemctl is-active查状态 -
TimeoutStopSec=120:Oracle正常关库可能耗时较长,尤其有大事务回滚,需延长超时
验证时用systemctl stop oracle-db后,立刻执行ps -ef | grep pmon和netstat -tlnp | grep :1521,两者都应为空。
最易被忽略的是/etc/oratab权限:它必须对oracle用户可读(644),否则dbstart/dbshut静默失败,systemd日志里只显示“exited with code 1”,得用journalctl -u oracle-db -n 50才能看到真实错误是“can't open /etc/oratab”。











