不能直接用主库service_name做读写分离,因为备库虽为只读模式,但未注册独立service_name时监听器无法区分路由,客户端连上后仍可发起写操作,导致ORA-16000报错或连接池打满;必须为主备库分别配置不同service_names(如prod_rw/prod_ro)并确保监听器动态注册且状态READY,再配合tnsnames.ora中对应别名及应用层正确选用,才能实现有效隔离。

为什么不能直接用主库 service_name 做读写分离
Oracle 12c ADG 的备库默认以 read only 模式打开,但数据库实例本身不自动提供只读服务名。如果业务连接串里写的还是主库的 service_name(比如 prod),哪怕连到了备库,Oracle 也不会拒绝写操作——它只是“允许你连”,不拦你发 INSERT 或 UPDATE。结果就是:语句报错(ORA-16000: database open for read-only access),或者更糟:应用没做异常兜底,反复重试导致连接池打满。
真正起隔离作用的是服务名(service_name)+ 监听器路由 + 客户端连接策略三者配合。主库和备库必须注册**不同**的 service_name,且监听器要能区分并正确转发。
如何在主库和备库分别配置读写专用 service_name
服务名不是靠改 tnsnames.ora 就能生效的,它由数据库实例动态注册到监听器,源头是 service_names 参数。这个参数可以动态修改,无需重启数据库。
- 主库(只写)执行:
ALTER SYSTEM SET service_names='prod_rw' SCOPE=BOTH; - 备库(只读)执行:
ALTER SYSTEM SET service_names='prod_ro' SCOPE=BOTH; - 确认生效:
SELECT value FROM v$parameter WHERE name = 'service_names'; - 检查监听器是否已注册(在主/备库服务器上运行):
lsnrctl status,输出中应看到对应service_name和status READY
注意:不要把 service_names 设成多个值(如 'prod_rw,prod_ro'),否则监听器会把两个服务都注册到同一实例,失去隔离意义。
tnsnames.ora 怎么配才能让应用自动走对库
tnsnames.ora 是客户端配置,它本身不决定读写分离,只提供连接入口。关键在于:应用代码或中间件是否按需选择不同的 alias。
典型配置示例(两端都要有):
PROD_RW =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = primary-host)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = prod_rw)
)
)
<p>PROD_RO =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = standby-host)(PORT = 1522))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = prod_ro)
)
)</p>常见错误:
- 把
PROD_RO的HOST写成主库地址——连得通,但实际还是连主库,毫无意义 - 没在备库监听器里开
prod_ro对应的静态服务(SID_LIST中漏配),导致lsnrctl status看不到该服务 - 应用连接池硬编码了
prod,没切换 alias,等于白配
容易被忽略的 ADG 同步状态校验点
即使服务名配对、tns 配置正确,如果备库没真正同步,prod_ro 连上去查到的就是过期数据。必须确认以下三项为真:
- 备库处于
MOUNT或READ ONLY WITH APPLY状态:SELECT open_mode, database_role FROM v$database;输出应为READ ONLY WITH APPLY - 日志正在实时应用:
SELECT process, status, sequence# FROM v$managed_standby WHERE process = 'MRP0';,status应为APPLYING_LOG - 主库归档已传到备库且未堆积:
SELECT archived_thread#, archived_seq#, applied_thread#, applied_seq# FROM v$archive_dest_status WHERE dest_id = 2;,确保archived_seq# == applied_seq#
ADG 的读写分离不是“配完就稳”,而是依赖持续的日志传输与应用链路;任何一环断开,prod_ro 就变成不可信的数据源。


















