警告:您的代码在多用户环境中存在缺陷。两个人可以同时运行查询并获得相同的 ID。如果列具有主键或候选键,其中一个将在 INSERT 上失败,这是键字段的最佳实践。
我的建议是让 ID 成为一个自动递增的整数字段(我不喜欢它们),或者更好的是,创建一个键表。表中的每条记录都用于分配键的表。我使用类似于这样的结构:
结构:countergenerator.dbf
数据库名称:conferencereg.dbc
长表名称:countergenerator
记录数:0
最后更新:2008 年 11 月 8 日
备忘录文件块大小:64
代码页:1252
表类型:Visual FoxPro 表
字段名称 类型 大小 空 下一步 默认
-------------------------------------------------- -------------------------------------------------- ------------
1 ccountergenerator_pk 字符 36 N guid(36)
2 ckey 字符(二进制) 50 Y
3 ivalue 整数 4 Y
4 mnote 备忘录 4 Y “自动创建”
5 cuserid 字符 30 Y
6 tupdated DateTime 8 Y DATETIME()
索引标签:
1. 标签名称:PRIMARY
- 类型:初级
- 关键表达式:ccountergenerator_pk
- 过滤器:(无)
- 顺序:升序
- 整理顺序:机器
2.标签名称:CKEY
- 类型:常规
- 关键表达式:lower(ckey)
- 过滤器:(无)
- 顺序:升序
- 整理顺序:机器
现在 DBC(或另一个程序)中存储过程的代码是这样的:
功能 NextCounter(tcAlias)
本地 lcAlias, ; ln下一个值,; lnOldReprocess, ; 旧区
lnOldArea = 选择()
如果 PARAMETERS() < 1 lcAlias = ALIAS()
IF CURSORGETPROP("SOURCETYPE") = DB_SRCLOCALVIEW *-- 尝试获取基表 lcAlias = LOWER(CURSORGETPROP("TABLES")) lcAlias = SUBSTR(lcAlias, AT("!", lcAlias) + 1) ENDIF ELSE lcAlias = LOWER (tcAlias) ENDIF
lnOrderNumber = 0 lnOldReprocess = SET('REPROCESS')
*-- 锁定直到用户按下 Esc SET REPROCESS TO AUTOMATIC
IF !USED("countergenerator") 使用 EventManagement!countergenerator IN 0 共享别名 countergenerator ENDIF
选择反发电机
IF SEEK(LOWER(lcAlias), "countergenerator", "ckey") IF RLOCK() lnNextValue = countergenerator.iValue REPLACE countergenerator.iValue WITH countergenerator.iValue + 1 UNLOCK ENDIF ELSE * 使用起始值创建新记录。APPEND BLANK IN countergenerator SCATTER MEMVAR MEMO m.cKey = LOWER(lcAlias) m.iValue = 1 m.mNote = "由存储过程自动创建。" m.tUpdated = DATETIME() 收集 MEMVAR 备忘录
IF RLOCK() lnNextValue = countergenerator.iValue 用 countergenerator.iValue + 1 UNLOCK ENDIF ENDIF 替换 countergenerator.iValue
SELECT (lnOldArea) 将重新处理设置为 lnOldReprocess
返回 lnNextValue ENDFUNC
RLOCK() 确保没有记录争用,并且速度足够快,不会出现瓶颈。这比您当前采用的方法更安全。
里克·舒默
VFP MVP