我原本用的是Access2000,后听说2000不支持事务处理,现已经改为Access2003版本了。
     我现在在做销售出库单保存按扭中的事件过程,此过程中,在保存完主表信息后,需要马上提取此条记录的自动编号内容给从表保存时用。原来试着用 AddNew 方法(ADO)和 Update 方法(ADO)来保存记录,虽然此方法能马上返回刚才所新增记录的自动编号,但这种方法绝对的不理想,在此就不多说了,现在改成用 insert into 语句来保存。但用insert into 语句来保存完成后,不知道在同一个过程中怎样能马上理想的提取到刚刚所保存的这条记录自动编号字段的内容。
    我曾用insert into 语句保存完后,再用select 语句查询主表信息,再提取此主表的最后一条记录的自动编号字段内容来用。可用这种方式,姑且先不考虑网络联机多用户操作的因素,仅单机使用,在测试了多遍后,就曾出现了一次错误,错误的提取了上一张单子的ID,而非刚刚保存的这张单子的ID,很吓人啊,可见此方法要枪毙了。
    我搜索网上的相关贴子,有这么个例句(insert into test(a,b) values('asd','ddd')  SELECT @@IDENTITY  as  id),似乎可以实现这个目的,但就在此贴的下楼就有一个朋友说“微软建议:最好少用@@identity,而用SCOPE_IDENTITY或IDENTITY_CURRENT来代替”,不知道是什么意思,让我心里又有些不着落了。
    我试着将自己的insert into 语句改成这样写:
Set Rs3 = Cnn.Execute ("insert into spxsb(ckzlID,wsttzlID,khzlID,xsbbh,qsbh,fphm,yfpsfxf,djxfdr,djxfsj,rq,hjje,bz,zdr)values " & _
        "(" + Str(Text1.text) + "," + Str(Text2.text) + "," + Str(Text3.text) + "," & _
        "'" + Trim(Right(Left(Trim(Label5.Caption), 15), 11)) + "'," & _
        "'" & Text9.text & "'," & _
        "'" & Text12.text & "'," & _
        "" & IIf(Check1.Value = 0, "0", " -1 ") & "," & _
        "'" & Label7.Caption & "'," & _
        "" & IIf(Not IsDate(Label8.Caption), "Null", "#" & Label8.Caption & "#") & "," & _
        "" & IIf(Not IsDate(DTPicker1.Value), "Null", "#" & DTPicker1.Value & "#") & "," & _
        "" & IIf(Trim(MSHFlexGrid2.TextMatrix(0, 3)) = "", "Null", Trim(MSHFlexGrid2.TextMatrix(0, 3))) & "," & _
        "'" & IIf(Trim(Text8.text) = "", Null, Trim(Text8.text)) & "','" + Trim(Label6.Caption) + "')" , i)
    可警告说:“SQL语句的结束位置缺少分号(;)”。因为本人是个新手,仅凭此贴中的只言片语还无法写出完整的SQL句子,只好又到这里求教来了。不知道走过路过的各位前辈高手们,你们是怎么实现这个目的的呢?

解决方案 »

  1.   

    晕Access2000怎会不支持事务?
    @@identity 是SQL server 的用法
    Access我一般用记录集对象(其中ID字段为自动编号)
    rst.add
    rst!字段2="22"
    rst.update
    debug.print rst!ID  这时候就是新值
      

  2.   

      我又找到了一个贴子,示例如下:  Jet4.0以后支持SELECT @@Identity语句,这条语句执行后会返回执行这条语句的connection对象最近一次插入的记录中的自动编号字段的值。请看例程:   cnn.execute "INSERT INTO Goods (Name,Description)Values ( '新商品1 ', '新商品描述1 ') " 
      dim rst as adodb.recordset 
      set rst=new adodb.recordset 
      rst.open "SELECT @@Identity " 
      msgbox rst(0)   '这里rst(0)即为新记录的自动编号字段的值  我试着照样子,引用到我的事件中执行后,倒也能顺利的执行下去,并不弹出警告,似乎语句写的并没错,可执行后返回的值始终是0,不知道怎么会事?我想如果当真SELECT @@Identity语句是这个贴子说明的这样,那可太妙了,那无论如何也要将它学会喽,还请各位高手不吝赐教,多帮忙了!
      

  3.   

        我用Access数据库,SELECT @@Identity 语句试来试去都是不行,可能yangzn76兄说的是对的,这个语句只适用于SQL server数据库。那么我暂时就不钻牛角尖了,采用junki兄的办法。
        那么,我又遇到了一个问题,再次请教各位,是关于事务处理的。
        还是在这个销售单保存按扭事件中。我放入了事务处理语句。
        首先,如果不放事务处理语句,这个过程执行的没问题,也就是说各条SQL语句写的都是对的。可是,加上事务处理后,在执行Cnn.CommitTrans'(提交事务)后,就会跳到出错块(照理说不用跳的),在执行Cnn.RollbackTrans'(错误回滚)时就弹出警告“试着不先使用BeginTrans而提交或退回事务。”,不知道是怎么会事?请高手们指点一下,谢谢!
      

  4.   


    在执行SQL前用Cnn.BeginTrans开始一个事务,
    在执行SQL后用Cnn.CommitTrans提交一个事务
    如果出错用Cnn.RollbackTrans回滚。
      

  5.   

    Access 数据库应该是单机版应用吧?你出错的原因是, SQL 语句是发送给 Jet 数据库引擎去执行的,因此和 VB 代码是异步的。也就是说,你读自增编号时不能保证新的插入已经完成。
    如果你是单机版,这个问题好解决。你只需在 cn.Execute 语句中加上 RecordsAffected 属性,就可以使插入完成后才继续执行后续语句:Dim n As Long
    cn.Execute strSQL, n......如果多用户版就比较麻烦。因为 Access 库不能锁表,只能锁记录。你无法保证所读记录是你新插入的。
      

  6.   

       先回复草上飞兄,我想我的事务处理语句正是如您这般写的。
       of123兄,如您所说,我可不可以这样理解:
       1、因为Access数据库是通过 Microsoft.Jet.OLEDB.4.0 数据库引擎去执行数据库操作的,所以,不管2000、2003,或是更高版本,百分百的都不能执行数据库事务处理语句(Cnn.BeginTrans开始一个事务;Cnn.CommitTrans提交一个事务;Cnn.RollbackTrans回滚。);
       2、Access数据库,只能锁记录,不能锁表。功能欠缺;
       3、综上所述,总之一句话,Access数据库不适合做为多用户版的应用程序的数据库,只适合做单机版的。
       of123兄,请赎我赘言,我这个理解对吗?如果我理解的没错,那么请教一下,如果我想做多用户应用程序的话(企业进销存管理软件),应该选择什么数据库比较好呢?就是此数据库技术目前已经比较成熟,而且相关的书籍教材(中文版的)等也比较丰富的。您看,是不是SQL server数据库?
      

  7.   

    1. Access 可以处理事务。
    2. Access 不是服务型数据库,而是文件型,主要是为单用户应用设计的。当然,它可以支持多用户。
    3. 进销存这类应用,一般不会大量用户并发访问,用 Access 应该可以。但最好设计成 C/S 架构,由 Server 端来访问数据库。
      

  8.   

    在准备数据插入之前取得目前数据库中ID字段的最大值;
    最大值加1就是下一条记录的ID值了,可以用这一数据进行必要的操作。
    设置成自动增长型时在插入记录时通常不太在意下一条记录的ID号,这样做是为了先行明确。
      

  9.   

        哎呦我的娘咧!本来,听您那样说,我差不多是绝望了,睡了一晚上后也是绝望打算了。可现在又听您这么说,我这心呦,又给勾引的痒痒的啊!那么,既然Access这么争气呼,岂有不拿下之理,of123兄,小弟这就要仰仗您多多指教了,你给个QQ或邮箱,咱们交个朋友怎么样?那我可荣幸之至了!我的QQ是76950746。
         回正题。
         一:从网上贴子上看来的,听说事务处理有3种形式,1、写在存储过程中,我不太懂,Access能做这种形式的事务处理吗?2、直接写在VB的代码中,这个我差不多应该算有点懂了吧,目前正在尝试,正如我上楼所提问的,为什么会弹出警告“试着不先使用BeginTrans而提交或退回事务。”,of123兄您看这是怎么回事呢?3、跨多服务器事务处理,这个目前我就不奢望懂了。
        of123兄,如果Access能在存储过程中事务处理的话,我们应该怎么写这种事务处理?我们有这个必要采用这种方式吗?这种方式相对于第2种方式有什么好处呢?一般都是在什么情况下采用这种方式来事务处理呢?
        二:您说让我最好能设计成 C/S 架构,由 Server 端来访问数据库。不怕您见笑,我真是孤陋寡闻啊,对这个一点也没感念呢。我心痒难耐,求知若渴,能不能请您耐心的跟我说一下,C/S 架构是什么概念?用Access数据库的话,具体应该怎么设计成 C/S 架构,由 Server 端来访问数据库呢?小弟拜谢了!
      

  10.   

    建议你不要这样设计,你这样的需求用自定义ID号更好
    事务处理由ADO支持,好象和什么数据库无关吧?当然许多数据库,特别是提供网络服务的数据库自身也提供事务处理
      

  11.   

    插入语句执行之后的第一条语句使用@@identity
    是支持ACCESS的,一般用这个就行了
      

  12.   

      怎么?Access数据库真的支持@@identity语句吗?本来我是很兴奋的,有这样好东西那还不妙极。我也曾找到示例,示例如下:  cnn.execute "INSERT INTO Goods Name,Description) Values ( '新商品1 ', '新商品描述1 ') " 
      dim rst as adodb.recordset 
      set rst = new adodb.recordset 
      rst.open "SELECT @@Identity " 
      msgbox rst(0)   '这里rst(0)即为新记录的自动编号字段的值   我照着样子测试了,可返回的值始终是0。再接着找贴子。有人说需要使用ADOX的Catalog对象创建,其方法是:
       cat.Create "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\NewJet4.MDB; " 
       这个我就不能理解了,ADO不都是用ADODB.Connection对象创建连接的吗?唉,总之,如果真有懂的高手的话,您就帮人帮到底,给说个具体的,别勾引的我心里痒痒的,可又一知半解的弄不懂,那可真难受呦!
      

  13.   

    晕,使用方法的问题啊谁说不可以的?cnn.execute   "INSERT   INTO   Goods   Name,Description)   Values   (   '新商品1   ',   '新商品描述1   ')   " dim   rst   as   adodb.recordset   
        set   rst   =   new   adodb.recordset   
        rst.open   "SELECT   @@Identity as myid  from  Goods"  这样就可以了,跟SQL server的写法不一样
      

  14.   

    关键是一插入数据就引用"select @@identity from [表]",要写具体表的
      

  15.   

        这为兄弟,我照着你提供的样式,试了一下,还是不行嘛!真的郁闷死了,也不知道是我特别苯还是怎么的。我将我的代码贴出来,请您再帮忙看看啊!
      Cnn.Execute ("insert into spxsb(ckzlID,wsttzlID,khzlID,xsbbh,qsbh,fphm,yfpsfxf,djxfdr,djxfsj,rq,hjje,bz,zdr)values " & _
        "(" + Str(Text1.text) + "," + Str(Text2.text) + "," + Str(Text3.text) + "," & _
        "'" + Trim(Right(Left(Trim(Label5.Caption), 15), 11)) + "'," & _
        "'" & Text9.text & "'," & _
        "'" & Text12.text & "'," & _
        "" & IIf(Check1.Value = 0, "0", " -1 ") & "," & _
        "'" & Label7.Caption & "'," & _
        "" & IIf(Not IsDate(Label8.Caption), "Null", "#" & Label8.Caption & "#") & "," & _
        "" & IIf(Not IsDate(DTPicker1.Value), "Null", "#" & DTPicker1.Value & "#") & "," & _
        "" & IIf(Trim(MSHFlexGrid2.TextMatrix(0, 3)) = "", "Null", Trim(MSHFlexGrid2.TextMatrix(0, 3))) & "," & _
        "'" & IIf(Trim(Text8.text) = "", Null, Trim(Text8.text)) & "','" + Trim(Label6.Caption) + "')"), i
      Dim rst As ADODB.Recordset
      Set rst = New ADODB.Recordset
      rst.Open "SELECT @@Identity as myid from spxsb ", Cnn, adOpenStatic, adLockOptimistic
      MsgBox rst.Fields("myid")  '这里rst(0)即为新记录的自动编号字段的值。    您看,我那里写的不对呢?都照着你的样式写的了,可 MsgBox 函数返回的值依然是0。急死了。
      

  16.   

       这位兄弟,我试过了,还是不行耶。我是仅向前、键集、动态、静态等类型游标都试过了,可返回的值依然都是0。真不好意思啊,让你多费心了,如果真能学会这个的话,我会很感激你的。当然,现在也很感激你的。呵呵!    Dim rst As ADODB.Recordset
        Set rst = New ADODB.Recordset
        rst.Open "SELECT @@Identity as myid from spxsb ", Cnn, adOpenKeyset, adLockOptimistic
        MsgBox rst.Fields("myid")
      

  17.   

    对了,问一句,你表里头有没有自动编号?有没建立主键和索引?还有PrimaryKey是不是升序,如果为降的话肯定是0,因为第1之前就是0
      

  18.   

    我是VB6.0 + Access2000,商品销售表,就是spxsb 表中绝对的有自动编号字段,是主键,有索引,升序。
    如果您有意加我QQ的话,我的QQ号是76950746
      

  19.   

        真心的感谢这位喜欢抽烟的兄弟,是他给予了耐心的帮助,现在将他提供的例程贴在这里,供需要的朋友参考。   Dim rss As Recordset
       Set rss = New Recordset
       rss.Open "insert into zhzl(mc) values('bbbbbbbbbbbbbb')", Cnn, adOpenKeyset, adLockPessimistic  '键集类型游标,保守式锁定
       rss.Open "select @@identity from zhzl"
       MsgBox "新增的ID为:" & rss.Fields(0).Value   这段代码绝对是通得过的,也就是说 @@identity 语句是适用于 Access2000 数据库的。另外补充几句我的心得:要用 @@identity 语句的话,新增记录时得用 Open 方法,后面的参数应该得用键集。
       我以前也是喜欢用 Open 方法的,但因为我不懂的 Open 方法后坠的两个参数的应用,我以前总是采用静态游标和开放式锁定,那样在执行SQL的时候,程序总是在SQL还未执行完毕的时候就已经去执行SQL语句下方的代码了,这样困扰了我很长的一段时间。现在得到了 Phenlit 兄弟的指导,总算让我茅塞顿开啊,现在采用键集和保守式锁定,问题一切搞定。
       晓事后,既然可以用 Open 方法了,那么我原来用 Update 方法(ADO)来保存数据,能更方便的得到刚才新建记录的自动编号字段内容的。现将我的代码贴出,给朋友们借鉴。   Dim Rs4 As New ADODB.Recordset
       If Rs4.State <> adStateClosed Then Rs4.Close
       Rs4.Open "Select * from cgjspycyb where gyszlID=" + Trim(Text6.text) + " order by cgjspycybID asc", Cnn, adOpenKeyset, adLockPessimistic  '键集,保守式锁定
       Rs4.AddNew  'AddNew 方法(ADO):为可更新的 Recordset 对象创建新记录。
      Rs4.Fields("gyszlID") = Text6  '供应商资料ID
      Rs4.Fields("spzlID") = MSHFlexGrid1.TextMatrix(MSHFlexGrid1.Row, 6)  '商品资料ID
      If MSHFlexGrid1.TextMatrix(MSHFlexGrid1.Row, 7) <> "" Then Rs4.Fields("hsyj") = MSHFlexGrid1.TextMatrix(MSHFlexGrid1.Row, 7) Else Rs4.Fields("hsyj") = Null
       Rs4.Update  'Update 方法(ADO):保存对 Recordset 对象的当前记录所做的所有更改。
       MSHFlexGrid1.TextMatrix(h, 4) = Rs4.Fields("cgjspycybID")  '将刚才所新建的记录自动编号字段内容读取到当前行的第4列。