怎么样处理在同时增加记录时,流水号不会出错?

dos123 2002-02-07 09:50:34
流水号是按照从1到n的顺序排下来的,如果在同一时间,有两个用户同时增加记录,这时
就有可能出现相同的流水号,而导致出错,怎么处理???????
...全文
83 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhuzhichao 2002-02-18
  • 打赏
  • 举报
回复
以下是后台用Oracle的方案,SQLServer也是一样的.

为了解决重号、跳号的问题,我们一般这样做:
1、建立一个序号表
2、在申请新的序列值的时候,先用Update将序列字段的值+1,但是不做commit,这样,相应的记录就被锁定;
3、判别SQLCode,如果成功,则说明这个序列值没有人使用,接着做4。不成功则提示稍候再试并Rollback;
4、用select取出序列值,+1后就是新的序列值;
5、把新序列值和相关数据进行对数据表的Insert,如果成功就接着做6。注意,对序号表的Update和对数据表的Insert是在一个事务里的,因此一旦对数据表的Insert操作失败而Rollback,则序号表的Update操作也被Rollback。这样一来,新的序列值并没有被真正commit到后台数据库里,还可以再一次使用,不会出现跳号的现象
6、commit。这样一来,数据表新增一条数据、序号表的相关序号+1。整个事务完成。:)

我们在PB中的解决方法,供参考:
xhb 序号表的结构
名称 空? 类型
----------------------------------------- -------- ------------
LBDM 类别代码 NOT NULL CHAR(2)
LBMC 类别名称 NOT NULL VARCHAR2(20)
NF 年份 NOT NULL VARCHAR2(8)
QZ 前缀 NOT NULL VARCHAR2(2)
XH 序号 NOT NULL NUMBER(8)
Unique Index = LBDM + NF + QZ

f_xh //定义一个取序号的函数,主要目的是锁记录和取新序号值
参数说明:
String as_lbdm 类别代码 传值 value
String as_lbmc 类别名称 传值 value
String as_nf 年份 传值 value
String as_qz 前缀 传值 value
Integer an_xh 序号 传址 reference

UPDATE xhb SET xh = xh + 1 WHERE lbdm = :as_lbdm AND nf = :as_nf AND qz = :as_qz USING SQLCA;//更新序号值,锁定记录,但不提交
IF SQLCA.SQLCode = 0 THEN
IF SQLCA.SQLNRows = 0 THEN
//如果没有相关记录,则插入新的序号记录
INSERT INTO xhb ( lbdm,lbmc,nf,qz,xh ) VALUES (:as_lbdm,:as_lbmc,:as_nf,:as_qz,1 );
IF SQLCA.SQLCode <> 0 THEN
ROLLBACK USING SQLCA;
RETURN FALSE
END IF
an_xh = 1//序号初始值为1
ELSE
SELECT xh INTO :an_xh FROM xhb WHERE lbdm = :as_lbdm AND nf = :as_nf AND qz = :as_qz USING SQLCA;//取出序号
END IF
ELSE
ROLLBACK USING SQLCA;
RETURN FALSE
END IF
RETURN TRUE

在程序中取序号则这幺写:
变量说明:
Integer li_xh 序号
String ls_xh 序号
Date gd_date 当前日期
String is_htlb 合同类别
DataWindow dw_kh 数据窗口
IF f_xh("01","虚拟计斤单号",String(gd_date,"YYYY"),is_htlb,li_xh) = False THEN
MESSAGEBOX("提示信息","取号失败!")
RETURN
END IF
// 如果f_xh执行成功,则li_xh中存放的应该是新的序号值,并且此时对此序号的记录锁并没有释放,别的用户不很再取新的序号值,这样,避免了重复取号的可能。
ls_xh = is_htlb+RIGHT(String(gd_date,"YYYY"),2)+f_padl(string(li_xh),5,'0') //组合出序号
//数据窗口数据更新
IF dw_kh.update() = 1 THEN
COMMIT USING SQLCA;
//如果数据窗口数据更新成功
//则提交整个事务(包括数据窗口更新和序号记录更新)
//对此序号记录的锁也被释放,其它用户可以继续取新的序号值
MESSAGEBOX("提示信息","合同配置成功!")
ELSE
ROLLBACK USING SQLCA;
//如果数据窗口数据更新失败
//则回滚整个事务(包括数据窗口更新和序号记录更新)
//序号保持原值,对此序号记录的锁被释放,其它用户可以继续取新的序号值
//避免了用sequence取过值就不能回滚的缺点
MESSAGEBOX("提示信息","合同配置失败!")
END IF
nana11 2002-02-18
  • 打赏
  • 举报
回复
再设计数据库表时,你可以把流水号的数据类型设计成indentity,这样就保证了不重复的情况。但是这样的话,数据不能保证是顺序的。
如果其他数据类型,比如整型,就在保存之前,你再取流水号,这样错出情况较小。
yccrane 2002-02-16
  • 打赏
  • 举报
回复
用indentity,没错.
如果你不喜欢indentity的话,用一个表来记录最大流水号(好像对于大流量数据来讲不太好).
yccrane 2002-02-16
  • 打赏
  • 举报
回复
用indentity,没错.
如果你不喜欢indentity的话,用一个表来记录最大流水号(好像对于大流量数据来讲不太好).
liulee 2002-02-08
  • 打赏
  • 举报
回复

看看 timeStamp 数据类型,你会有所启发的。

Oldman 2002-02-08
  • 打赏
  • 举报
回复
你可以把流水号设置成主键,在更新时侦测一下就可以避免。
zuoyangguang 2002-02-08
  • 打赏
  • 举报
回复
将流水号设为主键,在itemchanged中加入代码:
select count(*) into :ll_count from table where colunmname = :data;
if ll_count > 0 then
messagebox('提示信息','咔叽随风倒的')
return 1
end if
自动增量是数据库里的东东,有数据库自己加一,用户无法改变。
dos123 2002-02-08
  • 打赏
  • 举报
回复
不知道自增量怎么用
programbcb 2002-02-07
  • 打赏
  • 举报
回复
如果你用SQL SERVER的话,可以用indentity例,它会自动进行管理的。
双子东宝 2002-02-07
  • 打赏
  • 举报
回复

我的想法是,在提交事物的时候从相应的表中提取最大的流水号加一赋给新添加的记录。

ColdWolf 2002-02-07
  • 打赏
  • 举报
回复
有没有信号量啊
WaitingYou 2002-02-07
  • 打赏
  • 举报
回复
我以前也出现过这种争用现象,流水号若不能弄成自增量的,从根本上是无法避免的,比如帐务系统,只能减少这种碰撞
用存储过程,利用事务回滚功能
dos123 2002-02-07
  • 打赏
  • 举报
回复
小弟不才,能否提供一些代码让我瞧瞧!!!!
jeking 2002-02-07
  • 打赏
  • 举报
回复
流水号在提交时产生,或使用indentity
konrong 2002-02-07
  • 打赏
  • 举报
回复
可以在数据库中设置为自动增加字段.
ldk 2002-02-07
  • 打赏
  • 举报
回复
在insert之前把自动提交设为否,再判断数据库中是否存在该流水号,如果存在,自动加1再循环判断,直到该流水号是唯一的,然后insert,完成后把自动提交设为真,这样肯定不会造成流水号冲突,但速度会慢
jnhnsh 2002-02-07
  • 打赏
  • 举报
回复
检索最大流水号,加一即可,出现相同流水号的机率应该很小。
阿鹏兄 2002-02-07
  • 打赏
  • 举报
回复
同意顶楼jnhnsh的留言
trace2002 2002-02-07
  • 打赏
  • 举报
回复
我同意konrong(康尼)的方法,利用这种方法肯定成功

401

社区成员

发帖
与我相关
我的任务
社区描述
PowerBuilder 非技术版
社区管理员
  • 非技术版社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧