关于使用外部数据源时,在网络多用户并发情况下的不重复编号的申请的解决方案:
目前有2套方案供大家选用。两者相同之处在于系统产生的编号都是自动加1的,申请后未使用的编号都不再收回。不同之处在于申请编号的时间点不同。
第一个方案是在用户申请时,系统及时产生一个新的不重复的编号显示反馈给用户,可在DataRowAdding中应用。一个是在保存时才由系统产生一个新的不重复的编号,在BeforeSaveDataRow中应用(见:http://www.foxtable.com/dispbbs.asp?BoardID=2&ID=1727&replyID=&skin=1)。
以下是我在实际应用中使用的方法(申请时获取编号):
先建立数据库,表名:getnumberid,字段有:
Tablename 表名
Colname 列名
Preletter 前缀字符
Len 序列号长度
Sqdate 申请时间
number 当前序列号
此主题相关图片如下:getnumberid.jpg
在设计之前,要知道SQL的2个锁的概念。我摘录文章如下:
SQL Server的基本锁是共享锁(S锁)和排它锁(X锁)。
共享锁(S锁):用于不更改或不更新数据的操作(只读操作),如 SELECT 语句。共享锁锁定的资源可以被其他用户读取,但其他用户无法修改它,在执行Select时,SQL Server会对对象加共享锁。
排它锁(X锁): 用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。执行数据更新命令时,SQL Server会自动使用独占锁。当对象上有其他锁存在时,无法对其加独占锁。
一般情况下,SQL Server能自动提供加锁功能,不需要用户专门设置。
当用SELECT语句访问数据库时,系统能自动用共享锁访问数据;在使用INSERT、UPDATE和DELETE语句增加、修改和删除数据时,系统会自动给使用数据加排它锁。
以下是获取不重复编号的自定义函数。
'举例: Functions.Execute("getnumber","cgswbc","xtbh")
'参数1:表名,字符型,如"cgswbc"
'参数2:列名,字符型,是参数1的表中列名,如"xtbh"
'-----------------------------------------------------------------------------
dim getbh as string 'return 编号
dim tbname as string=Args(0) '读参数1,表名
dim clname as string=Args(1) '读参数2,列名
dim sqldate,numdate as date 'SQL服务器时间,指定表的编号使用时间
Dim dt As DataTable
Dim dr As Datarow
Dim t As integer
dim xh as integer=0 'update所影响行数的结果作为循环依据
dim numpre,numlen as string '准备存放前缀字符,序列号长度
dim num as integer ' '准备存放表中当前序号
Dim cmd As New SQLCommand
cmd.C
cmd.CommandText = "select getdate()"
sqldate=cmd.ExecuteScalar() '读SQL系统日期
do
cmd.CommandText = "select ISNULL(sqdate,GETDATE()) AS sqdate ,preletter,len, ISNULL(number,0) AS number from getnumberid where tablename='" & tbname & "' and colname='" & clname & "'"
dt = cmd.ExecuteReader() '读行记录
if dt is nothing then
Exit Do '没有行记录则直接退出返回
end if
dr = dt.DataRows(0) '取记录的第一行
numdate=dr("sqdate")
numpre=dr("preletter")
numlen=dr("len")
num=dr("number")
t=(sqldate-numdate).TotalDays
if t>0 then
cmd.commandtext = "Update getnumberid Set number =1,sqdate='" & sqldate & "' where tablename='" & tbname & "' and colname='" & clname & "' and number=" & num ’(此处关键,先读编号,根据编号更新。即使100个用户并发,也只有一个用户能成功申请,其余99个用户会申请失败,将会重新循环申请。)
xh=cmd.ExecuteNonQuery()
num=1 ' 新的一天,序列号置1
numdate=sqldate '填上新的日期
else
cmd.commandtext = "Update getnumberid Set number =" & num+1 & " where tablename='" & tbname & "' and colname='" & clname & "' and number=" & num
xh=cmd.ExecuteNonQuery()
num=num+1
end if
getbh=numpre.Trim() & "-" & CStr(numdate.year).SubString(2) & CStr(numdate.Month).PadLeft(2 ,"0") & CStr(numdate.Day).PadLeft(2 ,"0") & "-" & CStr(num).PadLeft(numlen ,"0")
Loop While xh=0
return getbh
------------------