You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle TAC与Python DML操作RAC故障转移异常问题求助

Oracle RAC故障转移:Python oracledb厚模式下DML操作无法完成节点切换

我在测试Oracle TAC与Python的结合使用,环境为Python 3.11,通过oracledb厚模式建立连接。目前遇到的问题是:执行查询操作时,Oracle RAC节点故障可正常切换至另一节点;但执行DML操作时,连接会直接断开,无法完成故障转移。经测试,相同场景在sqlplus和Java环境下可正常运行,已确认数据库及服务配置无误。

相关信息

Python代码

import oracledb
import db_config
import threading
import time

# Create a Connection Pool
pool = oracledb.create_pool(user=db_config.user,password=db_config.pw,dsn=db_config.dsn, min=4, max=5,increment=1,events=True,getmode=oracledb.POOL_GETMODE_NOWAIT)


def run_update():
    with pool.acquire() as conn:
        with conn.cursor() as cursor:
            conn.autocommit = False
            print("run_update(): beginning execute...")
            cursor.execute("SELECT sys_context('USERENV','INSTANCE_NAME') AS Instance FROM dual")
            res, = cursor.fetchone()
            print("Connected to instance: " +res)
            input("Press the Enter key to continue: ") 
            print("run_update(): beginning update...")
            sql = """SELECT UNIQUE CLIENT_DRIVER
                FROM V$SESSION_CONNECT_INFO
                 WHERE SID = SYS_CONTEXT('USERENV', 'SID')"""
            for r, in cursor.execute(sql):
             print(r)
            # populate table with a few rows
            stmt = "Update test SET v=UPPER(v) Where ID=:n"
            try:
                for i in range(5000):
                   cursor.execute(stmt, {'n': i})
                   if i == 250:
                     print("kill node")
                     input("Press the Enter key to continue: ") 
                     i = i + 1
            except oracledb.DatabaseError as e:
                print(e)
            else:
             cursor.execute("SELECT sys_context('USERENV','INSTANCE_NAME') AS Instance FROM dual")
             res, = cursor.fetchone()
             print("after stop connected to instance: " +res)
    

thread1 = threading.Thread(target=run_update)
thread1.start()


print("All done!")

服务配置

Service name: pdb_tac
Server pool:
Cardinality: 2
Service role: PRIMARY
Management policy: AUTOMATIC
DTP transaction: false
AQ HA notifications: true
Global: false
Commit Outcome: true
Failover type: AUTO
Failover method:
Failover retries: 1
Failover delay: 3
Failover restore: AUTO
Connection Load Balancing Goal: LONG
Runtime Load Balancing Goal: NONE
TAF policy specification: NONE
Edition:
Pluggable database name: pdb
Hub service:
Maximum lag time: ANY
SQL Translation Profile:
Retention: 86400 seconds
Replay Initiation Time: 600 seconds
Drain timeout: 30 seconds
Stop option: immediate
Session State Consistency: AUTO
GSM Flags: 0
Service is enabled
Preferred instances: orcl1,orcl2
Available instances:
CSS critical: no
Service uses Java: false

连接字符串

'(DESCRIPTION=(CONNECT_TIMEOUT=60)(RETRY_COUNT=30)(RETRY_DELAY=3)(TRANSPORT_CONNECT_TIMEOUT=4)(FAILOVER=ON)(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=rac-scan.localdomain)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME = pdb_tac.localdomain)))'

错误信息

run_update(): beginning execute...
Connected to instance: orcl2
Press the Enter key to continue:
run_update(): beginning update...
python-oracledb thk : 1.4.2
kill node
Press the Enter key to continue:
DPY-4011: the database or network closed the connection
DPI-1080: connection was closed by ORA-41429

解决方案

1. 启用TAF(Transparent Application Failover)配置

当前服务配置中TAF policy specification: NONE是核心问题。查询操作仅依赖连接层面的故障转移即可,但DML属于有状态事务,需要TAF维护会话状态并完成故障转移。

修改服务的TAF策略:

EXEC DBMS_SERVICE.MODIFY_SERVICE('pdb_tac', FAILOVER_TYPE => 'SESSION', FAILOVER_METHOD => 'BASIC', TAF_POLICY => 'BASIC');

或使用srvctl命令:

srvctl modify service -db your_db_name -service pdb_tac -failovertype SESSION -failovermethod BASIC -tafpolicy BASIC

修改后重启服务:

srvctl stop service -db your_db_name -service pdb_tac
srvctl start service -db your_db_name -service pdb_tac

2. 调整事务异常处理逻辑

在DML操作的异常捕获中,针对连接断开类错误添加重试机制,从断点处恢复事务:

except oracledb.DatabaseError as e:
    error_obj, = e.args
    print(f"Error occurred: {error_obj.message}")
    # 匹配RAC节点故障相关错误码
    if error_obj.code in [41429, 12537, 12541]:
        print("Attempting failover retry...")
        with pool.acquire() as new_conn:
            with new_conn.cursor() as new_cursor:
                new_conn.autocommit = False
                # 从故障发生的位置开始重试DML
                for j in range(i, 5000):
                    new_cursor.execute(stmt, {'n': j})
                new_conn.commit()
                res, = new_cursor.execute("SELECT sys_context('USERENV','INSTANCE_NAME') AS Instance FROM dual").fetchone()
                print(f"Retry succeeded, connected to instance: {res}")

3. 升级oracledb驱动版本

当前使用的python-oracledb thk : 1.4.2存在部分RAC故障转移兼容性问题,建议升级至最新稳定版:

pip install --upgrade oracledb

4. 完善连接字符串的故障转移参数

在连接字符串中明确指定TAF模式,增强故障转移的可靠性:

'(DESCRIPTION=(CONNECT_TIMEOUT=60)(RETRY_COUNT=30)(RETRY_DELAY=3)(TRANSPORT_CONNECT_TIMEOUT=4)(FAILOVER=ON)(FAILOVER_MODE=(TYPE=SESSION,METHOD=BASIC))(ADDRESS_LIST=(LOAD_BALANCE=on)(ADDRESS=(PROTOCOL=TCP)(HOST=rac-scan.localdomain)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME = pdb_tac.localdomain)))'

内容的提问来源于stack exchange,提问作者cptkirkh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 21:29:55