
简介Absolute Database Multi User Source v7.90 是一套面向 Delphi 开发者的数据库组件完整源码包适合需要在 Delphi 项目中集成多用户数据库能力的中高级程序员用于替换 BDE 或自研数据访问层解决单机与网络环境下数据并发访问、事务处理与索引维护等问题。压缩包共 567 个文件约 6.94MB以 sql 与 sqm 脚本、pas 与 dpk 源码单元、res 与 dfm 窗体资源、c/cpp/h 及 obj 等跨平台编译文件为主另含 bdsproj、dproj、bpk 等工程文件与少量 chm、hlp 帮助文档覆盖从源码到示例工程的完整结构。目前已有 262 人学习下载。读者可获得全部组件源码便于深入理解数据库引擎的查询解析、缓存管理与多用户锁机制并可直接在 Delphi 与 CBuilder 各版本中编译调试按需裁剪或扩展功能是研究嵌入式数据库实现与二次开发的实用参考。1. 拆开 Absolute Database 多用户源码包v7.90 里到底装了什么如果你正在给 Delphi 或 CBuilder 项目找一套能直接嵌进 EXE、不依赖外部数据库服务的本地存储方案Absolute Database 大概率在你的候选清单里躺了很久。这次拿到的是Absolute_Database_Multi_User_Source_v7.90注意后缀里的两个关键词Multi_User 和 Source。前者意味着它支持多用户并发访问同一份数据文件后者意味着你拿到的是完整源码而不是只有编译好的 DCU 或 BPL。这两点决定了它的使用方式和普通单机版组件完全不同。我拆这个包的第一反应是它解决的是「桌面应用要多人共享数据但又不想装 SQL Server 或 MySQL」这个经典矛盾。典型场景是局域网内几台机器跑同一套进销存、门诊挂号或车间报工系统数据文件放在共享目录各客户端直接读写。适合谁适合那些用 Delphi 做 C/S 架构、对部署简易度有执念、又需要看源码做二次定制的团队。不适合谁不适合需要跨公网高并发、或者对 SQL 标准兼容性要求极高的项目。2. 多用户模式的底层机制锁粒度、缓存与文件共享2.1 多用户并发到底靠什么撑住Absolute Database 的多用户能力不是靠一个独立服务进程而是靠文件级共享加记录级锁实现的。每个客户端进程直接打开同一个.abs数据文件通过操作系统文件映射和自定义的锁表来协调读写。源码包里你能找到ABSMultiUser相关的单元里面定义了锁的申请、释放和超时逻辑。关键参数是LockTimeout默认值通常在源码的常量区能看到。它的含义是当一个客户端要修改某条记录而另一个客户端已经锁住它时前者最多等多少毫秒。超过就抛异常。这个值设太小高并发下频繁报锁冲突设太大界面卡死用户以为程序崩了。我一般会在 3000 到 5000 之间取具体看业务写入频率。另一个核心是缓存策略。每个客户端会缓存一部分数据页读操作优先走缓存。多用户环境下缓存失效靠的是文件变更通知和版本号比对。源码里TABSDataSet的Refresh方法就是干这个的。如果你发现 A 机器改了数据B 机器要等很久才看到先查缓存刷新策略别急着怀疑锁。2.2 源码包目录结构与编译前准备解压后典型目录结构如下不同分发版本可能略有差异以实际为准目录/文件用途Source/核心源码单元含多用户锁、SQL 解析、存储引擎Packages/Delphi/CBuilder 包工程文件Demos/多用户示例通常含一个 C/S 演示Docs/帮助文件或接口说明Lib/预编译的 DCU 或 OBJ按编译器版本分目录编译前必须确认三件事第一你的 IDE 版本和包工程里的{$IFDEF}条件匹配第二Source/路径已加入 Library Path第三如果之前装过单用户版或旧版先把旧的 BPL 从 IDE 里卸载否则会出现「单元重复定义」的玄学报错。# 以 Delphi 为例检查当前已安装的包 # 在 IDE 菜单 Component - Install Packages 里查看 # 如果有 AbsoluteDB 相关旧包先 Remove # 然后打开 Packages/ 下对应版本的 .dpk 或 .dproj # 编译前确认搜索路径包含 Source 目录上面这段不是代码是操作顺序。很多人跳过卸载旧包这一步结果编译通过但运行时加载了旧版 BPL多用户锁行为跟源码对不上查半天查不出原因。2.3 多用户示例的运行与验证Demos/里通常有一个多用户演示工程。跑起来之前把数据文件放到一个所有测试机都能访问的共享目录。然后同时在两台机器上启动客户端一台改数据另一台刷新看结果。// 典型的多用户连接设置 ABSDataSet.DatabaseName : \\Server\Share\Data\demo.abs; ABSDataSet.LockTimeout : 4000; // 锁等待 4 秒 ABSDataSet.Open; // 修改前先进入编辑状态锁在这一刻申请 ABSDataSet.Edit; ABSDataSet.FieldByName(Qty).AsInteger : 100; ABSDataSet.Post; // 提交时释放锁逻辑说明DatabaseName指向共享路径多用户模式下所有客户端必须用完全一致的路径字符串映射盘符和 UNC 路径混用会导致锁表对不上。LockTimeout是每个数据集实例独立的不是全局。Edit触发锁申请Post触发锁释放和缓存失效广播。如果Post抛异常先看异常消息里的锁持有者信息源码里保留了持有者机器名和线程 ID这是排查锁冲突最直接的线索。3. 从源码到可用组件编译、安装与最小可用工程3.1 编译源码包的顺序与常见报错不要一上来就编译所有包。正确顺序是先编译运行时包Runtime Package再编译设计时包Design Package。运行时包只含核心逻辑设计时包依赖运行时包并提供 IDE 里的组件面板注册。// 运行时包工程里通常能看到类似条件编译 {$IFDEF VER340} // Delphi 10.4 Sydney {$LIBSUFFIX 104} {$ENDIF} {$IFDEF VER350} // Delphi 11 Alexandria {$LIBSUFFIX 110} {$ENDIF}这段条件编译决定了 DCU 输出目录后缀。如果你用的 IDE 版本不在源码支持列表里要么手动加条件分支要么把LIBSUFFIX统一改成一个固定值。我一般选后者省事但要注意不同版本编译器生成的 DCU 不兼容别把不同 IDE 编出来的 DCU 混在同一个输出目录。常见报错「Unit ABSMain was compiled with a different version of ...」几乎都是 DCU 版本混乱导致的。解决办法删掉所有Lib/下的预编译 DCU强制从源码重新编译并确保 Library Path 里Source/排在Lib/前面。3.2 安装到 IDE 与组件面板设计时包编译成功后右键 Install。组件面板会出现 Absolute Database 页签里面通常有TABSDataSet、TABSQuery、TABSTable等。如果没出现检查设计时包的Register单元是否被条件编译排除掉了。// Register 单元里注册组件的典型写法 procedure Register; begin RegisterComponents(Absolute Database, [TABSDataSet, TABSQuery]); end;参数说明RegisterComponents的第一个参数是面板页签名称你可以改成自己项目习惯的名字。第二个参数是组件类数组。如果编译时提示找不到TABSDataSet说明运行时包的单元没被正确引用检查设计时包的requires列表里有没有运行时包。3.3 最小可用多用户工程搭建新建一个 VCL 工程放一个TABSDataSet设置DatabaseName指向共享.abs文件再放一个TDataSource和TDBGrid连起来。这就是最小可运行的多用户客户端。// FormCreate 里打开数据集 procedure TForm1.FormCreate(Sender: TObject); begin ABSDataSet1.DatabaseName : \\192.168.1.10\Shared\demo.abs; ABSDataSet1.LockTimeout : 4000; ABSDataSet1.Open; end; // 一个简单的写入按钮 procedure TForm1.btnWriteClick(Sender: TObject); begin try ABSDataSet1.Edit; ABSDataSet1.FieldByName(Name).AsString : Test; ABSDataSet1.Post; except on E: Exception do ShowMessage(写入失败: E.Message); end; end;逻辑说明Open时如果文件不存在多用户模式下不会自动创建需要先用单用户模式或管理工具建库。Edit到Post之间是锁持有窗口尽量别在这中间弹对话框或做耗时操作否则其他客户端会一直等锁。异常处理里把E.Message直接显示出来Absolute Database 的锁冲突消息里通常包含持有者信息对定位问题很有用。4. 避坑与排查多用户环境下最容易翻车的五个点4.1 现象两台机器同时写入一台报「Lock timeout」原因锁等待时间设得太短或者写入事务持有锁的时间过长。多用户模式下Edit到Post之间的所有操作都在锁保护范围内如果中间有ShowMessage或循环计算锁会被长时间占用。解决把LockTimeout调到 5000 以上做测试确认是超时问题后再优化业务逻辑把耗时操作移到Edit之前或Post之后。源码里锁申请是阻塞式的没有异步回调所以只能靠缩短持锁时间来降低冲突概率。4.2 现象A 机器改了数据B 机器刷新后还是旧值原因缓存失效通知没生效。多用户模式下每个客户端有本地缓存文件变更通知依赖操作系统和源码里的版本比对逻辑。如果共享目录的变更通知被防火墙或网络策略拦截B 机器就收不到失效信号。解决先手动调用ABSDataSet.Refresh看能否拿到新值。如果手动刷新有效说明是自动通知的问题检查共享目录的 SMB 配置和防火墙规则。源码里Refresh会强制重新读取当前记录不走缓存。我一般会在关键业务界面上加一个定时Refresh间隔 2 到 3 秒作为通知失效时的兜底。4.3 现象编译通过运行时提示「Cannot open database」原因路径字符串不一致。多用户模式下锁表是按路径字符串哈希的。如果一台机器用映射盘符Z:\Data\demo.abs另一台用 UNC\\Server\Share\Data\demo.abs即使指向同一个文件锁表也认为是两个不同的数据库。解决统一用 UNC 路径或者在所有客户端上统一映射相同的盘符。源码里没有对路径做规范化处理这个坑只能靠部署规范来避。我现在的习惯是部署文档里明确写死用 UNC谁用映射盘符谁自己负责。4.4 现象数据文件越来越大多用户访问越来越慢原因多用户模式下删除记录不会立即回收空间而是标记为已删除。锁表和缓存页的元数据也会随操作次数增长。源码里没有自动压缩机制。解决定期用单用户模式打开数据文件调用Pack或类似方法整理空间。注意整理期间必须确保没有其他客户端连接否则会损坏文件。我一般选在业务低峰期用脚本先踢掉所有客户端再执行整理。4.5 现象源码编译出的组件和预编译 DCU 行为不一致原因Lib/下的预编译 DCU 可能是旧版本或者编译时的条件编译开关和源码默认值不同。多用户锁的超时默认值、缓存页大小这些参数在不同编译配置下可能不一样。解决彻底删掉Lib/目录全部从源码编译。如果必须用预编译 DCU先用源码里的常量定义和 DCU 反编译结果做比对确认关键参数一致。这个坑最隐蔽因为编译能过运行时才暴露而且现象不稳定。5. 进阶用源码定制锁策略与性能验证源码包最大的价值不是「能用」而是「能改」。多用户锁的申请逻辑在ABSMultiUser单元里你可以根据业务特点调整锁粒度。比如默认是记录级锁如果你的业务是批量导入逐条锁开销太大可以考虑在源码里加一个「批量模式」开关在批量操作期间申请表级锁一次性锁住整张表导入完再释放。// 源码里锁申请的核心逻辑示意简化 function TABSMultiUser.LockRecord(TableID, RecID: Integer; Timeout: Cardinal): Boolean; begin Result : False; // 先查锁表看目标记录是否已被锁 if not IsLocked(TableID, RecID) then begin // 未被锁写入锁表记录持有者信息 SetLock(TableID, RecID, GetCurrentThreadID); Result : True; end else begin // 已被锁等待 Timeout 毫秒后重试 Result : WaitForLock(TableID, RecID, Timeout); end; end;逻辑说明IsLocked查锁表SetLock写锁表WaitForLock是带超时的重试循环。如果你想加批量模式可以在SetLock之前判断一个全局标志如果批量模式开启直接锁整张表而不是单条记录。参数Timeout来自数据集实例的LockTimeout属性源码里没有做上限限制设成 0 就是立即返回失败设成INFINITE就是无限等待后者在多用户环境下基本等于自杀。验证方法改完源码后用两台机器跑压力测试。一台机器循环写入另一台循环读取观察锁冲突率和平均等待时间。源码里可以加日志把每次锁申请和释放的时间戳打出来用 Excel 或脚本分析。我一般会关注两个指标锁冲突率超过 5% 就说明锁粒度太粗平均等待时间超过 500ms 就说明持锁时间太长。还有一个技巧把LockTimeout做成可配置的从配置文件或注册表读而不是硬编码在源码里。这样现场部署时不用重新编译就能调。源码里加一个全局变量在Initialization段从INI文件读取赋值给默认值。这个改动很小但现场排障时能省很多事。从那以后我每次拿到带源码的数据库组件都强制走一遍「删预编译 DCU、全源码编译、双机锁冲突测试」这三步不再相信任何「开箱即用」的默认配置。希望帮到你。本文还有配套的精品资源点击获取