吵吵   2014-08-02  阅读:1,869

讨论这个问题的原因,最初来自于惠侨的工程师。我们医院用的HIS是军卫的系统,该系统的数据库是oracle的,在医生开具检验申请的时候,orcle有个序列发生器,用来生成唯一的test_no。但是当这个问题放到sql server里面来的时候,我们发现好像没法做?

此外,真正要解决这个问题,还源于我做的试剂耗材的管理系统。以往生成条码为了保证唯一性,使用日期时间+序列的方式,为了保证它不重复,时间就取的很细,到了毫秒级别。虽然理论上来讲这仍然有重复的可能性。

其实重复毕竟是小概率,但是条码却太长了,比如一个试剂的条码是20140801162430234001,这么一大串,一来不容易被条码枪识别,二来即便识别也容易造成识别前半部分。如果实在没有识别要手输的话,就是要费很大的工夫了。

条码本来就是类似数据库主键的意味,只要保证不重复,就该越短越好。

既然sql server没有序列发生器,那么我们还是用表来做吧。

基本的思路是建立一个有自增ID,时间,序号的表,取每天的该表的序号,每取一次就加一,并且写回该表。那么条码就是日期+序号了。

那么要解决的问题是,如果同时有两个程序都在读取和修改这张表,那该怎么办呢?

一、事务。由于想到事务是sql server里面的排它锁,因此认为只要程序中启用了事务,那么这个问题应该就能够解决,以下是测试的代码:

try
    dbquery.Connection.BeginTrans;
    dbquery.sql.clear;
    dbquery.SQL.Add('select * from lrm_bar where datediff("d",b_time,getdate())=0');
    dbquery.Open;
    if dbquery.RecordCount=0 then
    begin
      dbquery.sql.clear;
      dbquery.SQL.Add('insert into lrm_bar(b_time,b_num) values (getdate(),1)');
      if (dbquery.ExecSQL=1) then
      begin
        Result:= Self.NewBarHead+GetNumble(1);
        Query.Connection.CommitTrans;
      end;
    end
    else
    begin
      iNum:=dbquery.Int('b_num');
      strID:=dbquery.Str('b_id');
      iNum:=iNum+1;

      dbquery.sql.clear;
      dbquery.SQL.Add('update lrm_bar set b_num='+''''+Inttostr(iNum)+'''' +' where b_id='+''''+strID+'''');
      if (dbquery.ExecSQL=1) then
      begin
        Result:= Self.NewBarHead+GetNumble(iNum);
        Query.Connection.CommitTrans;
      end;

    end;


  except
    dbquery.Connection.RollbackTrans;
    result:='';
  end;

然后我启动两个程序,同时获取序列,发现有重复。因此得出结论,事务的锁应该仅限于该链接而已。

二、加锁。

那就只能够人工加锁了,把这个表锁住,直到我操作完了,才给别人操作。把上面的sql查询语句改为:

select * from lrm_bar with(TABLOCKX) where datediff(“d”,b_time,getdate())=0

TABLOCKX是sql server中强制使用独占表级锁,这个锁在事务期间阻止任何其他事务使用这个表。直到这个事务提交或者回滚。

之后我再同时测试两个程序同时获取序列:

A:01 03 05 07…
B:02 04 06 08…

OK不会再重复了。

三、条码长度。

解决了序列生成的问题,最后探讨一下条码长度的问题。

由于试剂一天入库数量不超过一千,那么序号就是001-999就足够了;日期的话年取1位,月份和日期各取两位,总共5位。那么生成的条码号就是8位,比原来的一大串短多了。

40801001,如果实在扫描不出,要手输入的话,看一遍就能输入完了,很方便。

序列生成到此完毕,如果你有更好的方法一定要告诉吵吵哦。

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

一条回应:“SQL SERVER的序列生成”

  1. silmark说道:

    获取序列号干嘛不用存储过程来写?SQLServer内存储过程的执行不是事务排队吗

发表评论

电子邮件地址不会被公开。 必填项已用*标注