假定表A为客户表,字段有:ID,NAME
有一个下拉框,里面为新客户名称的列表:cbxNew
现在想把这个下拉列表中的客户名称批量导入表A,同时为每个新客户自动生成ID,代码如下:ADOConnection.BeginTrans;
try
  for i:=0 to cbxNew.Items.Count-1 do
    with ado do
    begin
      Append;
      FieldByName('ID').AsString := GetID;//自动生成ID的一个函数
      FieldByName('NAME').AsString := cbxNew.Items[i];
      Post;
    end;
  ADOConnection.CommitTrans;
except
  ADOConnection.RollbackTrans;
end;我发现,如果这样做的话,插入第一条记录后就锁死了,去掉事务正常,将GetID函数改为常量也正常。研究了一下,可能原因就在于GetID这个函数,因为生成ID需要读取表A中的字段ID,使用事务后,第一条记录虽然post了,但并未生效,致使函数在读取ID字段时对新插入的记录的处理出现问题。现在问题就是,在使用事务的时候,如果在对一个表进行插入记录的同时,又需要不断读取该表某个字段,该如何处理呢?

解决方案 »

  1.   

    你的getid具体做了什么?
    应该可以不用每次读数据库的
      

  2.   

    建议建立一个规则, 比如你的id,先取到表中的id值,在循环中就不要在重复的Getid了,只把之前取到的id变量根据你的规则进行运行,比如+1等,然后付给新记录,最后一并提交
      

  3.   

    独立出来两个连接,或者,先读出A中最大ID存到程式里的变量,在程式里写函数
      

  4.   

    GetID的SELECT语句加上WITH(NOLOCK)试试
    SELECT max(ID) FROM tablename WITH(NOLOCK)
      

  5.   

    function GetID;
    begin
      Result := 0;
      while ado.Locate('ID',Result,[loCaseInsensitive])
        Result := Result + 1;
    end;
    这是个例子,实际代码复杂一些,但原理一致
      

  6.   

    你这个函数的意思基本上就是找一个没有用到的id嘛
    我建议你不如直接找MAX(ID),这样最简单,至于函数也不用了,批量更新前找到已用的最大ID,赋给变量i,更新的时候inc(i)就可以了
      

  7.   

    加上NOLOCK就可以了!
    看来就是因为启用了事务而导致表锁死,谢谢各位!
      

  8.   

    没错,直接去max(id),然后建立一个规则,赋值给新纪录即可
      

  9.   

        with ado do
        begin
          Append;       //处于dsInsert状态
          FieldByName('ID').AsString := GetID;//自动生成ID的一个函数
           FieldByName('NAME').AsString := cbxNew.Items[i];
          Post;
        end;ado.Locate  你又用这个来定位,有问题,Locate之后
    ado结果集已经定位到其他记录了.
      

  10.   

    哦,不好意思,我为了图方便省事,这个GetID函数是写在dll中的,两个ado不一回事,误导大家了,不好意思!
      

  11.   


    有道理,如果你的ID必须查询数据库才能得到,建议用sql语句,用insert