我原本用的是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句子,只好又到这里求教来了。不知道走过路过的各位前辈高手们,你们是怎么实现这个目的的呢?
我现在在做销售出库单保存按扭中的事件过程,此过程中,在保存完主表信息后,需要马上提取此条记录的自动编号内容给从表保存时用。原来试着用 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句子,只好又到这里求教来了。不知道走过路过的各位前辈高手们,你们是怎么实现这个目的的呢?
@@identity 是SQL server 的用法
Access我一般用记录集对象(其中ID字段为自动编号)
rst.add
rst!字段2="22"
rst.update
debug.print rst!ID 这时候就是新值
dim rst as adodb.recordset
set rst=new adodb.recordset
rst.open "SELECT @@Identity "
msgbox rst(0) '这里rst(0)即为新记录的自动编号字段的值 我试着照样子,引用到我的事件中执行后,倒也能顺利的执行下去,并不弹出警告,似乎语句写的并没错,可执行后返回的值始终是0,不知道怎么会事?我想如果当真SELECT @@Identity语句是这个贴子说明的这样,那可太妙了,那无论如何也要将它学会喽,还请各位高手不吝赐教,多帮忙了!
那么,我又遇到了一个问题,再次请教各位,是关于事务处理的。
还是在这个销售单保存按扭事件中。我放入了事务处理语句。
首先,如果不放事务处理语句,这个过程执行的没问题,也就是说各条SQL语句写的都是对的。可是,加上事务处理后,在执行Cnn.CommitTrans'(提交事务)后,就会跳到出错块(照理说不用跳的),在执行Cnn.RollbackTrans'(错误回滚)时就弹出警告“试着不先使用BeginTrans而提交或退回事务。”,不知道是怎么会事?请高手们指点一下,谢谢!
在执行SQL前用Cnn.BeginTrans开始一个事务,
在执行SQL后用Cnn.CommitTrans提交一个事务
如果出错用Cnn.RollbackTrans回滚。
如果你是单机版,这个问题好解决。你只需在 cn.Execute 语句中加上 RecordsAffected 属性,就可以使插入完成后才继续执行后续语句:Dim n As Long
cn.Execute strSQL, n......如果多用户版就比较麻烦。因为 Access 库不能锁表,只能锁记录。你无法保证所读记录是你新插入的。
of123兄,如您所说,我可不可以这样理解:
1、因为Access数据库是通过 Microsoft.Jet.OLEDB.4.0 数据库引擎去执行数据库操作的,所以,不管2000、2003,或是更高版本,百分百的都不能执行数据库事务处理语句(Cnn.BeginTrans开始一个事务;Cnn.CommitTrans提交一个事务;Cnn.RollbackTrans回滚。);
2、Access数据库,只能锁记录,不能锁表。功能欠缺;
3、综上所述,总之一句话,Access数据库不适合做为多用户版的应用程序的数据库,只适合做单机版的。
of123兄,请赎我赘言,我这个理解对吗?如果我理解的没错,那么请教一下,如果我想做多用户应用程序的话(企业进销存管理软件),应该选择什么数据库比较好呢?就是此数据库技术目前已经比较成熟,而且相关的书籍教材(中文版的)等也比较丰富的。您看,是不是SQL server数据库?
2. Access 不是服务型数据库,而是文件型,主要是为单用户应用设计的。当然,它可以支持多用户。
3. 进销存这类应用,一般不会大量用户并发访问,用 Access 应该可以。但最好设计成 C/S 架构,由 Server 端来访问数据库。
最大值加1就是下一条记录的ID值了,可以用这一数据进行必要的操作。
设置成自动增长型时在插入记录时通常不太在意下一条记录的ID号,这样做是为了先行明确。
回正题。
一:从网上贴子上看来的,听说事务处理有3种形式,1、写在存储过程中,我不太懂,Access能做这种形式的事务处理吗?2、直接写在VB的代码中,这个我差不多应该算有点懂了吧,目前正在尝试,正如我上楼所提问的,为什么会弹出警告“试着不先使用BeginTrans而提交或退回事务。”,of123兄您看这是怎么回事呢?3、跨多服务器事务处理,这个目前我就不奢望懂了。
of123兄,如果Access能在存储过程中事务处理的话,我们应该怎么写这种事务处理?我们有这个必要采用这种方式吗?这种方式相对于第2种方式有什么好处呢?一般都是在什么情况下采用这种方式来事务处理呢?
二:您说让我最好能设计成 C/S 架构,由 Server 端来访问数据库。不怕您见笑,我真是孤陋寡闻啊,对这个一点也没感念呢。我心痒难耐,求知若渴,能不能请您耐心的跟我说一下,C/S 架构是什么概念?用Access数据库的话,具体应该怎么设计成 C/S 架构,由 Server 端来访问数据库呢?小弟拜谢了!
事务处理由ADO支持,好象和什么数据库无关吧?当然许多数据库,特别是提供网络服务的数据库自身也提供事务处理
是支持ACCESS的,一般用这个就行了
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对象创建连接的吗?唉,总之,如果真有懂的高手的话,您就帮人帮到底,给说个具体的,别勾引的我心里痒痒的,可又一知半解的弄不懂,那可真难受呦!
set rst = new adodb.recordset
rst.open "SELECT @@Identity as myid from Goods" 这样就可以了,跟SQL server的写法不一样
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。急死了。
Set rst = New ADODB.Recordset
rst.Open "SELECT @@Identity as myid from spxsb ", Cnn, adOpenKeyset, adLockOptimistic
MsgBox rst.Fields("myid")
如果您有意加我QQ的话,我的QQ号是76950746
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列。