Delphi 32位应用数据库故障转移报错需重启问题的解决方法
故障转移无法自动恢复的核心原因
你碰到的两类报错是配置错误+Delphi5旧访问层缺陷+32位程序内存限制三者叠加导致的:
- 你当前配置的
provider=msoledb.1是Windows自带的老旧OLEDB驱动ProgID,根本不是你安装的18.3版MSOLEDBSQL驱动,直接导致multisubnetfailover=true等AG相关参数完全不生效 - Delphi 5自带的ADO封装默认没有失效连接自动回收逻辑,故障转移时被远程主副本强制断开的连接句柄会残存在内存和连接池中,既不会自动重连,也不会释放占用的内存,残片积累就会触发
-2147024882(0x8007000E)内存分配失败 - 18.3版驱动默认的连接重试、存活检测参数没有针对AG场景调优,故障转移后的TCP断开窗口内不会自动做透明重连
驱动与连接字符串配置调整
- 首先修正驱动ProgID,把连接字符串里的
provider=msoledb.1改成provider=MSOLEDBSQL.1,这一步不做后面所有配置都无效 - 在现有连接字符串基础上追加以下参数:
Connect Timeout=3; ConnectRetryCount=5; ConnectRetryInterval=1; Packet Size=4096; Connection Lifetime=30; OLE DB Services=-2;
参数说明:
ConnectRetryCount/ConnectRetryInterval是18.x驱动专为AG提供的透明重连参数,故障转移后驱动会在后台自动尝试重建连接,不需要上层代码感知Connection Lifetime=30强制连接池回收存活超过30秒的旧连接,避免业务拿到故障转移前的失效句柄OLE DB Services=-2关闭自动事务绑定和多余的连接池缓存,避免失效连接关联的事务句柄泄漏占用内存- 3秒连接超时配合
MultiSubnetFailover=True可以并行探测AG所有副本的IP,不会出现单IP超时卡几十秒的问题 - 修改32位EXE的PE头,开启大地址感知:在Delphi5的命令行环境下执行
editbin /LARGEADDRESSAWARE 你的程序.exe,让程序在64位Windows下可以用到4G用户态内存,大幅降低内存碎片触发分配失败的概率 - 调整客户端网卡TCP参数:把TCP keepalive时间从默认的2小时改成30秒,避免死连接长时间占用连接池
Delphi 5侧代码改造
- 废弃程序启动时初始化长连接、全局复用一个TADOConnection的写法,改成按需创建连接、用完立刻释放,所有数据集执行操作前先校验连接状态
- 封装统一的数据库执行入口,加异常重试逻辑:
- 捕获到
连接被远程主机关闭、内存分配失败、通信链路失败三类异常时,不要直接向上抛错 - 先调用当前连接的
Close()方法,手动释放所有关联的ADOCommand、ADODataSet对象,彻底销毁失效连接句柄 - 调用Windows API
CoFreeUnusedLibraries()强制释放OLEDB驱动持有的闲置内存块,解决内存残留导致的分配失败 - 间隔1秒重新打开连接,重试当前数据库操作,最多重试3次,3次都失败再抛出异常
- 捕获到
- 去掉TADOConnection组件OnError事件中直接终止程序的逻辑,故障转移时的单次连接断开属于可恢复错误,不要直接触发程序退出
- 增加轻量连接保活逻辑:每20秒执行一次
SELECT 1探测连接状态,一旦检测到连接失效立刻主动重建,不要等用户操作时才触发报错 - 如果你当前用的是BDE组件而不是原生ADO访问数据库,必须全部替换成ADO组件,BDE完全不支持AG的多子网故障转移特性,没有调优空间
验证注意事项
- 手动触发故障转移后预留3-5秒的重连窗口,不要立刻高频点击功能按钮
- 测试时不要在Delphi IDE调试模式下运行,IDE会拦截驱动层自动重试时抛出的第一次异常,直接编译为独立EXE运行测试
- 故障转移后可以通过执行
sp_who2确认新主副本上的连接来源,确认连接已经切到新节点
内容的提问来源于stack exchange,提问作者Sree
相关产品推荐
相关产品推荐

