解决办法其实就三条:
- 手动补全 `ORACLE_HOME_LISTNER=$ORACLE_HOME`,位置放在 `dbstart` 脚本开头(`#!/bin/bash` 下一行就行)。
- `/etc/oratab` 里的 `Y` 必须是大写,不能带空格或注释尾缀。比如 `ORCL:/u01/app/oracle/product/19c/dbhome_1:Y` 这样写。
- 另外要注意:`dbstart` 不会去校验密码文件、spfile 路径或 `local_listener` 配置,失败时只把日志写到 `$ORACLE_HOME/startup.log`,终端上完全看不到错误——这也是很多人折腾半天找不到原因的地方。
### systemd service 文件里为什么不能只写 `Environment=ORACLE_HOME=...`
systemd 启动服务时不会加载 `~oracle/.bash_profile` 或 `/etc/profile`,所以 `ORACLE_SID`、`PATH`、`LD_LIBRARY_PATH` 全是空的。只要漏了 `ORACLE_SID`,`dbstart` 就找不到对应的实例行,直接跳过启动,连个通知都没有。
更稳妥的做法是单独写一个轻量环境初始化脚本,比如 `/etc/profile.d/oracle_env.sh`,里面只放三行:
```
export ORACLE_HOME=/u01/app/oracle/product/19c/dbhome_1
export ORACLE_SID=ORCL
export PATH=$ORACLE_HOME/bin:$PATH
```
然后在 service 文件的 `ExecStart` 里改成这样:
```
/bin/bash -c 'source /etc/profile.d/oracle_env.sh && $ORACLE_HOME/bin/dbstart $ORACLE_HOME'
```
绝对不要尝试在 `Environment=` 行里拼接变量,比如 `Environment="PATH=$ORACLE_HOME/bin:$PATH"`——systemd 不会解析变量,它会原样把这个字符串传给进程,结果路径就变成了字面量的 `$ORACLE_HOME`,完全不可用。
### `Type=forking` 和 `Type=oneshot` 哪个更适合 Oracle 19c
从实际部署经验来看,`Type=forking` 更稳妥,但必须配上 `PIDFile`;`Type=oneshot` 看似简单,实际容易误判“启动完成”,导致后面依赖的服务提前启动,或者 `systemctl start` 返回过早,以为服务已经起来了,其实数据库还没完全就绪。
- 选 `Type=forking` 时,务必设置 `PIDFile=$ORACLE_HOME/dbs/lk$ORACLE_SID`(注意是 `lk` 开头的锁文件,不是 `.pid` 文件)。
- 选 `Type=oneshot` 的话,必须加上 `RemainAfterExit=yes`,否则服务状态会立刻变成 `inactive`,`systemctl is-active oracle.service` 查不到运行态。
- 不管用哪种类型,都建议加一行 `TimeoutSec=300`——`dbstart` 内部等待监听器默认是 15 秒,但在 ARM 平台或高负载下容易超时,systemd 会直接 kill 掉进程。
### 监听器和数据库的启动顺序怎么保障不踩坑
`dbstart` 内部虽然有等待逻辑,但它只执行一次 `lsnrctl status`,并不验证监听器是否真正注册了当前实例。最常见的现象是:监听器起来了,但 `sqlplus / as sysdba` 报 `ORA-12514: TNS:listener does not currently know of service requested`——监听器不认识这个数据库实例。
这里有几个实战建议:
- 不要用 `ExecStartPre` 单独启动监听器再启动数据库——这样绕过了 `dbstart` 对 `oratab` 的读取,实例很可能被忽略掉。
- 应该在 `dbstart` 执行后追加一个验证步骤。比如在 service 的 `ExecStartPost` 里加:
```
/bin/bash -c 'sleep 10 && $ORACLE_HOME/bin/sqlplus -S / as sysdba < /dev/null'
```
- 更关键的是检查数据库内部的 `local_listener` 配置:`show parameter local_listener` 必须指向正确的地址,然后执行 `alter system register;` 确保动态注册生效。
最后必须提一个最容易忽略的点:systemd 服务启动时,`oracle` 用户对 `$ORACLE_HOME/bin/` 下所有可执行文件必须有 `x` 权限,特别是 `dbstart`、`lsnrctl`、`sqlplus`。权限不对时,service 日志里只显示 “Permission denied”,不会告诉你具体哪个文件——排查起来相当头大。Oracle 19c自启动脚本配置与systemd服务单元文件编写指南
为什么直接改 ` etc oratab` 为 Y 还是不启动 这事其实挺让人迷惑的:明明已经把 ` etc oratab` 里的标记改成了 `Y`,可机器重启后数据库就是没起来。问题出在哪儿? 关键点在于 Oracle 19c 的 `dbstart` 脚本已经废弃了自动监听器启动逻辑。它硬编
### 为什么直接改 `/etc/oratab` 为 Y 还是不启动
这事其实挺让人迷惑的:明明已经把 `/etc/oratab` 里的标记改成了 `Y`,可机器重启后数据库就是没起来。问题出在哪儿?
关键点在于 Oracle 19c 的 `dbstart` 脚本已经废弃了自动监听器启动逻辑。它硬编码检查 `ORACLE_HOME_LISTNER` 环境变量——而这个变量在 19c 里默认根本没设,也不再由 `oraenv` 或 profile 自动导出。所以脚本一启动就报错:“ORACLE_HOME_LISTNER is not set, unable to auto-start Oracle Net Listener”。然后它直接跳过监听器启动,数据库也因为连不上监听而挂起或静默失败。
解决办法其实就三条:
- 手动补全 `ORACLE_HOME_LISTNER=$ORACLE_HOME`,位置放在 `dbstart` 脚本开头(`#!/bin/bash` 下一行就行)。
- `/etc/oratab` 里的 `Y` 必须是大写,不能带空格或注释尾缀。比如 `ORCL:/u01/app/oracle/product/19c/dbhome_1:Y` 这样写。
- 另外要注意:`dbstart` 不会去校验密码文件、spfile 路径或 `local_listener` 配置,失败时只把日志写到 `$ORACLE_HOME/startup.log`,终端上完全看不到错误——这也是很多人折腾半天找不到原因的地方。
### systemd service 文件里为什么不能只写 `Environment=ORACLE_HOME=...`
systemd 启动服务时不会加载 `~oracle/.bash_profile` 或 `/etc/profile`,所以 `ORACLE_SID`、`PATH`、`LD_LIBRARY_PATH` 全是空的。只要漏了 `ORACLE_SID`,`dbstart` 就找不到对应的实例行,直接跳过启动,连个通知都没有。
更稳妥的做法是单独写一个轻量环境初始化脚本,比如 `/etc/profile.d/oracle_env.sh`,里面只放三行:
```
export ORACLE_HOME=/u01/app/oracle/product/19c/dbhome_1
export ORACLE_SID=ORCL
export PATH=$ORACLE_HOME/bin:$PATH
```
然后在 service 文件的 `ExecStart` 里改成这样:
```
/bin/bash -c 'source /etc/profile.d/oracle_env.sh && $ORACLE_HOME/bin/dbstart $ORACLE_HOME'
```
绝对不要尝试在 `Environment=` 行里拼接变量,比如 `Environment="PATH=$ORACLE_HOME/bin:$PATH"`——systemd 不会解析变量,它会原样把这个字符串传给进程,结果路径就变成了字面量的 `$ORACLE_HOME`,完全不可用。
### `Type=forking` 和 `Type=oneshot` 哪个更适合 Oracle 19c
从实际部署经验来看,`Type=forking` 更稳妥,但必须配上 `PIDFile`;`Type=oneshot` 看似简单,实际容易误判“启动完成”,导致后面依赖的服务提前启动,或者 `systemctl start` 返回过早,以为服务已经起来了,其实数据库还没完全就绪。
- 选 `Type=forking` 时,务必设置 `PIDFile=$ORACLE_HOME/dbs/lk$ORACLE_SID`(注意是 `lk` 开头的锁文件,不是 `.pid` 文件)。
- 选 `Type=oneshot` 的话,必须加上 `RemainAfterExit=yes`,否则服务状态会立刻变成 `inactive`,`systemctl is-active oracle.service` 查不到运行态。
- 不管用哪种类型,都建议加一行 `TimeoutSec=300`——`dbstart` 内部等待监听器默认是 15 秒,但在 ARM 平台或高负载下容易超时,systemd 会直接 kill 掉进程。
### 监听器和数据库的启动顺序怎么保障不踩坑
`dbstart` 内部虽然有等待逻辑,但它只执行一次 `lsnrctl status`,并不验证监听器是否真正注册了当前实例。最常见的现象是:监听器起来了,但 `sqlplus / as sysdba` 报 `ORA-12514: TNS:listener does not currently know of service requested`——监听器不认识这个数据库实例。
这里有几个实战建议:
- 不要用 `ExecStartPre` 单独启动监听器再启动数据库——这样绕过了 `dbstart` 对 `oratab` 的读取,实例很可能被忽略掉。
- 应该在 `dbstart` 执行后追加一个验证步骤。比如在 service 的 `ExecStartPost` 里加:
```
/bin/bash -c 'sleep 10 && $ORACLE_HOME/bin/sqlplus -S / as sysdba < /dev/null'
```
- 更关键的是检查数据库内部的 `local_listener` 配置:`show parameter local_listener` 必须指向正确的地址,然后执行 `alter system register;` 确保动态注册生效。
最后必须提一个最容易忽略的点:systemd 服务启动时,`oracle` 用户对 `$ORACLE_HOME/bin/` 下所有可执行文件必须有 `x` 权限,特别是 `dbstart`、`lsnrctl`、`sqlplus`。权限不对时,service 日志里只显示 “Permission denied”,不会告诉你具体哪个文件——排查起来相当头大。
解决办法其实就三条:
- 手动补全 `ORACLE_HOME_LISTNER=$ORACLE_HOME`,位置放在 `dbstart` 脚本开头(`#!/bin/bash` 下一行就行)。
- `/etc/oratab` 里的 `Y` 必须是大写,不能带空格或注释尾缀。比如 `ORCL:/u01/app/oracle/product/19c/dbhome_1:Y` 这样写。
- 另外要注意:`dbstart` 不会去校验密码文件、spfile 路径或 `local_listener` 配置,失败时只把日志写到 `$ORACLE_HOME/startup.log`,终端上完全看不到错误——这也是很多人折腾半天找不到原因的地方。
### systemd service 文件里为什么不能只写 `Environment=ORACLE_HOME=...`
systemd 启动服务时不会加载 `~oracle/.bash_profile` 或 `/etc/profile`,所以 `ORACLE_SID`、`PATH`、`LD_LIBRARY_PATH` 全是空的。只要漏了 `ORACLE_SID`,`dbstart` 就找不到对应的实例行,直接跳过启动,连个通知都没有。
更稳妥的做法是单独写一个轻量环境初始化脚本,比如 `/etc/profile.d/oracle_env.sh`,里面只放三行:
```
export ORACLE_HOME=/u01/app/oracle/product/19c/dbhome_1
export ORACLE_SID=ORCL
export PATH=$ORACLE_HOME/bin:$PATH
```
然后在 service 文件的 `ExecStart` 里改成这样:
```
/bin/bash -c 'source /etc/profile.d/oracle_env.sh && $ORACLE_HOME/bin/dbstart $ORACLE_HOME'
```
绝对不要尝试在 `Environment=` 行里拼接变量,比如 `Environment="PATH=$ORACLE_HOME/bin:$PATH"`——systemd 不会解析变量,它会原样把这个字符串传给进程,结果路径就变成了字面量的 `$ORACLE_HOME`,完全不可用。
### `Type=forking` 和 `Type=oneshot` 哪个更适合 Oracle 19c
从实际部署经验来看,`Type=forking` 更稳妥,但必须配上 `PIDFile`;`Type=oneshot` 看似简单,实际容易误判“启动完成”,导致后面依赖的服务提前启动,或者 `systemctl start` 返回过早,以为服务已经起来了,其实数据库还没完全就绪。
- 选 `Type=forking` 时,务必设置 `PIDFile=$ORACLE_HOME/dbs/lk$ORACLE_SID`(注意是 `lk` 开头的锁文件,不是 `.pid` 文件)。
- 选 `Type=oneshot` 的话,必须加上 `RemainAfterExit=yes`,否则服务状态会立刻变成 `inactive`,`systemctl is-active oracle.service` 查不到运行态。
- 不管用哪种类型,都建议加一行 `TimeoutSec=300`——`dbstart` 内部等待监听器默认是 15 秒,但在 ARM 平台或高负载下容易超时,systemd 会直接 kill 掉进程。
### 监听器和数据库的启动顺序怎么保障不踩坑
`dbstart` 内部虽然有等待逻辑,但它只执行一次 `lsnrctl status`,并不验证监听器是否真正注册了当前实例。最常见的现象是:监听器起来了,但 `sqlplus / as sysdba` 报 `ORA-12514: TNS:listener does not currently know of service requested`——监听器不认识这个数据库实例。
这里有几个实战建议:
- 不要用 `ExecStartPre` 单独启动监听器再启动数据库——这样绕过了 `dbstart` 对 `oratab` 的读取,实例很可能被忽略掉。
- 应该在 `dbstart` 执行后追加一个验证步骤。比如在 service 的 `ExecStartPost` 里加:
```
/bin/bash -c 'sleep 10 && $ORACLE_HOME/bin/sqlplus -S / as sysdba < /dev/null'
```
- 更关键的是检查数据库内部的 `local_listener` 配置:`show parameter local_listener` 必须指向正确的地址,然后执行 `alter system register;` 确保动态注册生效。
最后必须提一个最容易忽略的点:systemd 服务启动时,`oracle` 用户对 `$ORACLE_HOME/bin/` 下所有可执行文件必须有 `x` 权限,特别是 `dbstart`、`lsnrctl`、`sqlplus`。权限不对时,service 日志里只显示 “Permission denied”,不会告诉你具体哪个文件——排查起来相当头大。来源:https://www.php.cn/faq/2692968.html
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。
相关推荐
补充同频道和同主题内容,方便继续浏览更多相关内容。
同类最新
继续查看同栏目最近更新的文章。
Java 17环境下Oracle驱动包ojdbc11依赖冲突详细解决方法指南
Java17环境下ojdbc11依赖冲突主要源于模块系统与驱动声明不匹配,典型表现为模块未找到、反射受限和类加载器隔离问题。需在module-info java中显式添加requiresoracle jdbc,配置--add-opens和--add-modules启动参数,同时确保classpath中无多个不同版本的ojdbc包以避免依赖冲突。
SQL JOIN查询各部门薪资前三名员工的高效方法
使用ROW_NUMBER()窗口函数配合PARTITIONBY按部门分组、按薪水降序编号,通过子查询或CTE筛选排名前三的记录,即可准确查询每个部门薪水最高的三名核心员工。避免使用GROUPBY与MAX(),因其无法获取员工姓名等详细信息。排序时需附加员工ID确保结果稳定,先计算排名再关联部门表可提升性能。
PostgreSQL INITCAP函数:姓名首字母转大写的方法
PostgreSQL的INITCAP函数仅适用于ASCII字符,无法处理中文姓名、全角符号及专有名词大小写(如MCDONALD→McDonald)。连字符和撇号被视为单词分隔符,但全角符号导致失效。批量更新前需谨慎筛选,建议在应用层或自定义函数中处理中文姓名。
SQL中RANK函数在特定分组内的排名方法
RANK()是窗口函数,不能与GROUPBY直接连用,否则报错。正确实现分组内排名需使用PARTITIONBY子句在窗口内排序。旧版MySQL不支持时,可通过自连接或应用层分组排序替代,但性能较差,建议升级数据库版本。
如何通过SQL视图屏蔽数据库引擎语法差异?
SQL视图无法屏蔽数据库引擎间的语法差异,因其依赖底层解析器和函数库。实现跨库兼容的策略包括:使用ORM自动翻译方言,按引擎分支编写视图,禁用非标准函数。需注意权限、字符集一致性及视图嵌套对性能的影响。
