简介:这份资源面向使用 PowerBuilder 开发数据库应用的开发者,聚焦远程连接 SQL Server 时 IP 地址不固定的实际难题,提供可参考的配置思路与示例工程。压缩包共 25 个文件,约 73KB,以 srf 窗口/函数源码、pbl 与 pbt 工程库、pbw 工作区为主,辅以 gif 界面截图、js 与 css 网页素材及 bat 批处理脚本,构成一套可直接打开研究的 PB 工程骨架。内容涉及 ODBC 数据源配置、动态 IP 下的域名映射与连接保持、SQL Server 远程访问与端口开放、连接失败后的重试处理等关键环节,读者可据此理解 PB 远程访问数据库的完整链路,并借鉴其中的函数封装与工程组织方式。目前已有 616 人学习下载,适合具备一定 PB 基础、需要解决动态网络环境下数据库连接问题的开发者参考。
1. 从一次“本地能连、远程就断”的翻车说起
上周帮某实验室把一套跑了七八年的 PowerBuilder 老系统接上远程 SQL Server,本地测试一切正常,换到异地办公点就报“数据库连接失败”,日志里连个像样的错误码都不给。这类 PB 连 SQL Server 的场景在存量系统里太常见了:客户端用 PB 6.5 到 PB 2019 的都有,服务端 SQL Server 从 2008 R2 到 2019 混着跑,网络那头还是动态 IP,今天通了明天可能就换地址。装不好不是报个错就完事,而是业务直接停摆,操作员干瞪眼。这篇笔记面向两类人:第一次接手 PB 老项目、需要把远程库连通的新手,以及想搞清楚动态 IP 下连接参数怎么取舍的熟手。下面按“环境先列清、再一步步装、最后能验证跑通”的顺序走,中间穿插我踩过的坑和后悔药。
2. 环境清单与版本选择:PB、SQL Server、ODBC 三件套怎么配
2.1 先定 PB 版本和数据库驱动,别让位数打架
PB 连 SQL Server 走的是 ODBC 或 OLE DB,核心矛盾往往不在 PB 本身,而在驱动位数。PB 6.5、PB 9 这类老版本是 32 位程序,只能加载 32 位 ODBC 驱动;PB 2017 之后才有 64 位运行时。常见做法是先确认 PB 可执行文件的位数,再决定装哪套驱动。查看方法很简单,任务管理器里看进程有没有“32 位”标注,或者直接看安装目录。
# 在客户端机器上确认 PB 运行时位数(Windows) # 方法一:任务管理器 -> 详细信息 -> 平台列 # 方法二:用 PowerShell 读 PE 头 $path = "C:\Program Files (x86)\Sybase\PowerBuilder 12.5\pb125.exe" $bytes = [System.IO.File]::ReadAllBytes($path) $peOffset = [BitConverter]::ToInt32($bytes, 0x3C) $machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4) # 0x014c = 32 位 x86,0x8664 = 64 位 x64 "{0:X4}" -f $machine这段脚本读的是 PE 文件头里的 Machine 字段,0x014c就是 32 位,0x8664是 64 位。为什么要较这个真?因为 32 位 PB 去调 64 位 ODBC 管理器里配的数据源,界面上根本看不到,配了也白配。我一般会先跑一遍这个判断,再决定打开“ODBC 数据源(32 位)”还是“ODBC 数据源(64 位)”。Windows 上两个管理器名字几乎一样,只有括号里的位数不同,这是第一个高频翻车点。
版本搭配上,PB 12.5 及以前配 SQL Server 2008 R2 用 SQL Native Client 10.0 比较稳;PB 2017/2019 配 SQL Server 2016 以上,直接用 ODBC Driver 17 for SQL Server。驱动不是越新越好,老 PB 对 ODBC 3.x 之后的某些接口支持不全,装最新驱动反而可能在连接时卡住。下面这张表是我整理过的常见组合,按实际项目验证过:
| PB 版本 | 位数 | 推荐驱动 | SQL Server 版本 | 备注 |
|---|---|---|---|---|
| PB 6.5 / 9 | 32 位 | SQL Native Client 10.0 | 2008 R2 | 老系统主力,驱动别乱升 |
| PB 12.5 | 32 位 | ODBC Driver 11 | 2012 / 2014 | 兼容性较好 |
| PB 2017 | 32/64 位 | ODBC Driver 17 | 2016 及以上 | 注意运行时位数 |
| PB 2019 | 64 位 | ODBC Driver 17/18 | 2017 及以上 | 新项目首选 |
2.2 SQL Server 侧要开的三样东西:协议、端口、账户
客户端折腾半天连不上,很多时候问题在服务端没开对。SQL Server 默认安装后,TCP/IP 协议经常是禁用的,只留了共享内存,本地能连、远程必断,这就是第 1 章那个场景的根因之一。打开 SQL Server 配置管理器,在“SQL Server 网络配置”下把 TCP/IP 启用,然后重启 SQL Server 服务。端口方面,默认实例走 1433,命名实例走动态端口,远程连接要么改成固定端口,要么在连接串里写实例名让客户端去 SQL Browser 服务问。
-- 在 SQL Server 上确认监听状态和端口 SELECT @@SERVERNAME AS server_name, SERVERPROPERTY('InstanceName') AS instance_name, SERVERPROPERTY('IsIntegratedSecurityOnly') AS windows_auth_only;IsIntegratedSecurityOnly返回 1 表示只允许 Windows 身份验证,这时候用 SQL 账户登录会被拒。远程场景下通常要改成混合模式:在 SSMS 里右键实例属性,安全性页选“SQL Server 和 Windows 身份验证模式”,重启服务生效。账户方面,别直接用 sa,建一个只对目标库有读写权限的登录名,密码策略按公司规范来。这一步看着琐碎,但后面动态 IP 切换时,账户和权限是唯一不变的东西,先把它们固定下来,排错时能少一半变量。
2.3 动态 IP 下连接串怎么写才不天天改配置
动态 IP 是这套环境最烦人的地方。PB 里数据库连接一般写在应用对象的 SQLCA 里,或者用 Profile 文件存连接参数。IP 一变,如果硬编码在代码里,就得重新编译发版,这在运维上不可接受。常见做法是把主机名、端口、库名、账户抽到外部配置文件,PB 启动时读进来再赋给 SQLCA。下面是一个 Profile 文件的写法,PB 的ProfileString函数能直接读:
; dbconn.ini —— 放在客户端程序同目录,IP 变了只改这里 [Database] DBMS=ODBC Database=erp_prod UserID=pb_app DBPass=****** ServerName=dbhost.internal Port=1433// PB 启动脚本里读取配置并赋值给 SQLCA string ls_server, ls_db, ls_user, ls_pass ls_server = ProfileString("dbconn.ini", "Database", "ServerName", "") ls_db = ProfileString("dbconn.ini", "Database", "Database", "") ls_user = ProfileString("dbconn.ini", "Database", "UserID", "") ls_pass = ProfileString("dbconn.ini", "Database", "DBPass", "") SQLCA.DBMS = "ODBC" SQLCA.Database = ls_db SQLCA.UserID = ls_user SQLCA.DBPass = ls_pass SQLCA.ServerName = ls_server SQLCA.AutoCommit = False CONNECT USING SQLCA; IF SQLCA.SQLCode <> 0 THEN MessageBox("连接失败", SQLCA.SQLErrText) END IF这里的关键取舍是ServerName填主机名而不是 IP。动态 IP 环境下,让内网 DNS 或者 hosts 文件把主机名指到当前地址,客户端配置一行不用动。如果连 DNS 都没有,退而求其次用 hosts,但要注意每台客户端都要维护,规模一大就失控。AutoCommit = False是 PB 连 SQL Server 的常规设置,事务由应用自己控制,别随手改成 True,否则批量操作时容易出现部分提交。端口写在配置文件里是为了命名实例场景,默认实例可以省略。
3. 客户端安装与 ODBC 数据源配置:从装驱动到连通
3.1 装 ODBC 驱动:位数、静默安装、验证三步走
驱动安装本身不复杂,坑在“装错位数”和“装完没验证”。以 ODBC Driver 17 for SQL Server 为例,32 位和 64 位是两个独立安装包,文件名里带 x86 和 x64。PB 是 32 位就装 x86 版,别图省事两个都装——两个都装本身没问题,但配数据源时容易在错误的管理器里操作。静默安装适合批量部署:
# 32 位驱动静默安装(管理员权限运行) msiexec /i msodbcsql17_x86.msi /quiet /norestart IACCEPTMSODBCSQLLICENSETERMS=YES # 安装后验证:列出已注册的 ODBC 驱动 reg query "HKLM\SOFTWARE\WOW6432Node\ODBC\ODBCINST.INI\ODBC Drivers" | findstr /i "SQL Server"IACCEPTMSODBCSQLLICENSETERMS=YES是微软驱动安装必须带的参数,不带会静默失败,日志里只留一行看不懂的返回码。/norestart避免安装程序擅自重启机器,生产环境客户端上这点很重要。验证那行注册表查询走的是WOW6432Node,也就是 32 位视图,能看到 “ODBC Driver 17 for SQL Server” 才算装对位置。64 位则查HKLM\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers。装完驱动先别急着配数据源,用系统自带的odbcad32.exe打开对应位数的管理器确认列表里有它,这一步能挡掉后面一半的“数据源配了但 PB 找不到”。
3.2 配一个系统 DSN,参数逐项说清
数据源分用户 DSN 和系统 DSN。PB 以服务方式跑或者多用户共用一台客户端时,用系统 DSN;单人桌面用用户 DSN 也行。我一般统一配系统 DSN,省得换账户登录后找不到。打开 32 位 ODBC 管理器(C:\Windows\SysWOW64\odbcad32.exe),添加 -> ODBC Driver 17 for SQL Server,逐项填:
| 配置项 | 填法 | 说明 |
|---|---|---|
| Name | PB_ERP | 连接串里引用的名字,别带空格 |
| Server | dbhost.internal,1433 | 主机名逗号端口,命名实例写 主机名\实例名 |
| 身份验证 | SQL Server 身份验证 | 填专用账户,不用 sa |
| 默认数据库 | erp_prod | 连上后默认切到这个库 |
| 加密 | 按服务端要求 | 老服务端可能只支持否 |
Server 那一栏的逗号端口写法很多人不知道,默认实例可以只写主机名,但一旦服务端改过端口,不写端口就连不上,报错还是笼统的“登录超时”。配完点“测试数据源”,成功会显示连接成功;失败的话先看错误号,18456 是登录失败(账户或密码问题),4060 是数据库不存在或无权限,08001 是网络层没通。这三个错误号基本能定位到八成问题,比盯着 PB 的报错框有用得多。
3.3 PB 里改用 ODBC 连接并做一次最小连通测试
数据源配好后,PB 侧把 DBMS 改成 ODBC,ServerName填 DSN 名字而不是主机名,这是和直连驱动写法最大的区别。很多人从 OLE DB 或直连方式迁过来时忘了改,结果 PB 把 DSN 名当主机名去解析,自然连不上。最小测试不用起整个应用,新建一个应用对象,在 Open 事件里写连接和一条查询:
// 最小连通测试:连上后查一行数据 SQLCA.DBMS = "ODBC" SQLCA.ServerName = "PB_ERP" // 这里填 DSN 名,不是 IP SQLCA.Database = "erp_prod" SQLCA.UserID = "pb_app" SQLCA.DBPass = "******" SQLCA.AutoCommit = False CONNECT USING SQLCA; IF SQLCA.SQLCode = 0 THEN MessageBox("OK", "连接成功,服务端版本:" + SQLCA.SQLNRows) ELSE MessageBox("FAIL", String(SQLCA.SQLCode) + " / " + SQLCA.SQLErrText) END IFSQLCA.ServerName赋 DSN 名这一点再强调一次,ODBC 模式下它代表数据源名称,不是网络地址。测试时如果SQLCode非 0,SQLErrText里通常带 ODBC 的原始错误,比应用层包装过的提示信息量大。连通之后别急着收工,再跑一条带参数的查询,确认字符集和日期格式没问题——PB 老版本对 Unicode 支持有限,中文乱码往往在这一步才暴露。
4. 避坑与排查:动态 IP 环境下最容易翻车的五件事
4.1 现象:本地通、远程断,报“未找到或无法访问服务器”
原因几乎都是服务端 TCP/IP 协议没启用,或者防火墙没放行 1433。SQL Server 默认安装只开共享内存,本地客户端走共享内存能连,远程只能走 TCP,协议一关就断。解决分两步:配置管理器里启用 TCP/IP 并重启服务;防火墙入站规则放行对应端口,命名实例还要放行 SQL Browser 的 UDP 1434。改完用telnet 主机名 1433或 PowerShell 的Test-NetConnection验证端口通不通,别直接拿 PB 试,PB 的报错信息太少,容易误判。
4.2 现象:ODBC 管理器里配好了,PB 就是找不到数据源
原因是位数不匹配。32 位 PB 只认 32 位 ODBC 管理器里配的 DSN,而很多人从开始菜单打开的是 64 位那个。判断方法:在 PB 里连不上时,用C:\Windows\SysWOW64\odbcad32.exe打开管理器看 DSN 在不在列表里;不在就说明配到了 64 位那边。解决是把 DSN 在对应位数的管理器里重配一遍,或者干脆两个位数都配同名 DSN,省得以后换程序又踩。这个坑我见过太多次,血泪经验是:配 DSN 之前先确认 PB 位数,别凭感觉。
4.3 现象:昨天能连,今天 IP 一变全挂
动态 IP 环境下硬编码 IP 的必然结果。原因不用多说,解决思路是把连接参数外置,用主机名加内网 DNS 解析,或者至少用 hosts 集中管理。如果连 DNS 都没有,退一步在客户端加一个启动时探测的逻辑:先解析主机名,失败则读备用地址列表,逐个尝试。但这是权宜之计,长期还是要把名字解析做起来。另外提醒一句,动态 IP 切换后 SQL Server 的证书或加密配置如果绑了旧地址,也可能连带出问题,切换后跑一遍完整连接测试再放业务上线。
4.4 现象:连接成功但查询报“未将对象引用设置到对象的实例”之类怪错
这类错误往往不是网络问题,而是驱动版本和 PB 运行时不匹配。老 PB 配了新 ODBC Driver 18,某些接口返回结构变了,PB 解析不了。解决是回退到表格里推荐的驱动版本,别追新。另一个常见诱因是AutoCommit设置和事务隔离级别冲突,批量更新时偶发。排查时先把连接串简化到最小,逐项加回参数,用二分法定位是哪个配置项引入的。
4.5 现象:多客户端并发时随机断连,日志无规律
先查服务端连接数上限和客户端连接池配置。PB 默认不复用连接,每个应用实例占一个,客户端一多就容易触顶。SQL Server Express 版有 10GB 库大小和资源限制,并发一高就表现异常。解决是服务端确认版本和连接上限,客户端侧在应用退出时确保DISCONNECT USING SQLCA执行到,别让连接泄漏。动态 IP 环境下还要注意网络设备的老化连接回收时间,长事务跨过回收点会被静默断开,表现就是随机断连。这类问题没有银弹,只能靠日志和抓包慢慢缩小范围。
5. 装完怎么验证跑通:一套可复现的连通性检查清单
装完不等于跑通,我习惯用一套固定顺序的检查把变量逐个排除,顺序是:网络层 -> 驱动层 -> 数据源层 -> 应用层。网络层用Test-NetConnection 主机名 -Port 1433,通不过就别往下走;驱动层查注册表确认位数和驱动名;数据源层用odbcad32.exe的测试按钮;应用层跑第 3 章那个最小 PB 测试程序。四层都过,才算这套环境真的立住了。
# 一键跑完前三层检查(在客户端执行) $host = "dbhost.internal"; $port = 1433 # 第一层:端口连通 $tcp = Test-NetConnection -ComputerName $host -Port $port -WarningAction SilentlyContinue "TCP 1433: " + $tcp.TcpTestSucceeded # 第二层:32 位驱动是否注册 $drv = reg query "HKLM\SOFTWARE\WOW6432Node\ODBC\ODBCINST.INI\ODBC Drivers" 2>$null | Select-String "ODBC Driver 17" "Driver 32bit: " + [bool]$drv # 第三层:DSN 是否存在 $dsn = reg query "HKLM\SOFTWARE\WOW6432Node\ODBC\ODBC.INI\PB_ERP" 2>$null "DSN PB_ERP: " + [bool]$dsn这段脚本把三层检查串起来,输出三个布尔值,全 True 才继续。Test-NetConnection的-Port参数会真的发起 TCP 握手,比 ping 靠谱,因为很多服务器禁 ping 但端口是通的。注册表路径里的WOW6432Node对应 32 位视图,和 PB 位数保持一致。DSN 检查查的是ODBC.INI下的键,存在说明系统 DSN 配好了。三层都过之后,再跑 PB 测试程序,如果还失败,问题就锁定在应用层配置,范围小很多。
验证通过后还有一件事:把这次用的驱动版本、DSN 名、配置文件模板、检查脚本归档到项目文档里。动态 IP 环境迟早要再折腾一次,下次换人接手时,有这套东西能省掉大半天。从那以后我每次交付 PB 远程连接环境,都强制走一遍这四层检查,不跳步、不凭感觉,因为跳过的那一步往往就是下次翻车的伏笔。希望帮到你。
本文还有配套的精品资源,点击获取