如何在Advantage本地服务器(ALS)中用SQL锁定记录避免并发更新?
针对Advantage本地服务器(ALS)的记录冲突解决建议
方案1:利用ALS的悲观记录锁定机制
ALS原生支持悲观记录级锁定,你可以通过Delphi的TAdsTable组件(而非TQuery)实现,步骤如下:
- 将组件的
LockType属性设置为ltPessimistic(悲观锁模式) - 打开表后,通过唯一ID定位目标记录
- 调用
Edit方法触发锁定,此时其他用户无法修改该记录,直到你执行Post提交或Cancel取消编辑
示例Delphi代码:
var AdsTable: TAdsTable; begin AdsTable := TAdsTable.Create(nil); try AdsTable.Connection := YourALSConnection; AdsTable.TableName := 'target_table'; AdsTable.LockType := ltPessimistic; AdsTable.Open; // 通过唯一ID定位待更新记录 if AdsTable.Locate('unique_id', TargetRecordID, []) then begin AdsTable.Edit; // 锁定当前记录 AdsTable.FieldByName('number').AsInteger := UpdatedValue; AdsTable.Post; // 提交后自动释放锁 end; finally AdsTable.Free; end; end;
方案2:乐观锁实现(低冲突场景首选)
如果不想因悲观锁导致记录长时间锁定,可采用乐观锁逻辑,核心是更新时验证记录是否被篡改:
- 给数据表新增一个版本字段(如
version,整数类型,每次更新自增)或时间戳字段(last_modified) - 查询记录时同时获取版本号/时间戳
- 更新时携带该值,仅当数据库中对应记录的版本号/时间戳与查询值一致时,才执行更新操作
示例SQL逻辑(基于版本号):
-- 查询记录及版本号 SELECT number, version FROM target_table WHERE unique_id = :TargetID; -- 带验证的更新语句 UPDATE target_table SET number = :NewValue, version = version + 1 WHERE unique_id = :TargetID AND version = :OriginalVersion;
执行更新后检查受影响行数:若返回0,说明记录已被其他用户修改,需提示用户重新获取最新数据后再操作。
方案3:表级独占锁(极端场景使用)
若需确保整个操作周期内记录完全不被访问,可给表加独占锁,但注意这会阻塞其他用户对该表的所有操作,仅适合极短时间的操作:
AdsTable.Exclusive := True; AdsTable.Open; // 执行更新操作 AdsTable.Close; // 关闭表后释放独占锁
关于你之前代码的说明
你之前的SELECT number FROM table WHERE 1=1语句不会锁定任何记录,ALS默认查询为快照读取模式,不会对记录施加锁,因此无法起到冲突预防作用。
内容的提问来源于stack exchange,提问作者Leo Bidi
相关产品推荐
相关产品推荐

