以文本方式查看主题

-  Foxtable(狐表)  (http://foxtable.net/bbs/index.asp)
--  专家坐堂  (http://foxtable.net/bbs/list.asp?boardid=2)
----  [分享]:在网络多用户并发情况下的申请不重复编号的解决方案  (http://foxtable.net/bbs/dispbbs.asp?boardid=2&id=4177)

--  作者:yuanbin
--  发布时间:2009/9/2 12:29:00
--  [分享]:在网络多用户并发情况下的申请不重复编号的解决方案

关于使用外部数据源时,在网络多用户并发情况下的不重复编号的申请的解决方案:

目前有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
------------------

--  作者:yangming
--  发布时间:2009/9/2 12:31:00
--  
学习研究!
--  作者:czy
--  发布时间:2009/9/2 12:37:00
--  
先顶一个。
--  作者:狐狸爸爸
--  发布时间:2009/9/2 12:43:00
--  
呵呵,袁斌的帖子都是重量级的
--  作者:程兴刚
--  发布时间:2009/9/2 12:58:00
--  
顶!
--  作者:kylin
--  发布时间:2009/9/2 15:48:00
--  
好帖,顶一下,谢谢!
--  作者:migold
--  发布时间:2009/9/3 9:31:00
--  
顶,高手

能否做个实例共享,看文字不是很懂
--  作者:99473593
--  发布时间:2013/7/28 17:33:00
--  

学学


--  作者:zhy400137
--  发布时间:2016/9/23 21:36:00
--  
照做了,为什么一运行就死机?
--  作者:找到没重的名
--  发布时间:2021/3/20 17:32:00
--  
学习一下