尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

VB6+Access数据库操作指南:从ADO连接到并发控制

VB6+Access数据库操作指南:从ADO连接到并发控制 简介这是一份讲解VB6与Access数据库联动开发的PDF文档面向初学桌面数据库编程的VB6开发者重点解决如何在传统VB6工程中通过ADO组件高效操作Access数据库。文档开篇说明引用Microsoft ActiveX Data Objects 2.7库的步骤清晰展示Connection对象建立连接、Recordset对象执行SQL并遍历结果以及用Execute方法完成增删改查的完整写法四个实例依次覆盖组合框数据绑定、用户登录校验、窗体加载自动连接和标准SQL执行代码可直接复制改造。资源为单个PDF文件大小仅26KB内容短小精悍已有98人学习。适合希望快速掌握VB6Access操作要点的初学者按照示例修改表名、字段和连接路径后即可嵌入自己的数据库项目中。1. VB6Access 数据库操作二十年后还在跑方法得落到命令上老工厂的产线系统、财务的遗留账单、医院的设备登记模块至今仍有一批 VB6 编译的 exe 在 Windows 上运行旁边的 Access 数据库文件从 XP 时代活到现在。所谓数据库操作方法核心无非是连接怎么建、数据怎么增删改查、界面怎么绑定、并发写入怎么控制这几件事但每一件都有固定参数和容易踩的坑ADO 连接串选错 Provider或 32 位驱动装成 64 位程序直接报找不到提供程序DataGrid 编辑完忘了 UpdateBatch数据看着在界面上一关窗体全部丢失。这篇按实际接手老项目的顺序把 VB6Access 的数据库操作方法完整过一遍适合维护遗留系统或准备做数据迁移的工程师照着改。2. ADO 连接 Access驱动选择、连接串参数与释放规范2.1 为什么是 ADO 而不是 DAO 或 ODBCVB6 时代操作 Access 有三条路线DAO 直接驱动 Jet 引擎对表结构、索引的控制最细但离开了 Access 场景就几乎无用ODBC 是通用底座要配置 DSN适合被其他语言混合调用的老系统ADO 是基于 OLE DB 的中间层同时兼容 Access、SQL Server、OracleRecordset 对象模型统一。今天接手别人的 VB6 项目十有八九代码里已经是 ADO新写的维护补丁也建议用 ADO否则两种对象模型混在一个工程里Dim 声明、游标规则、错误号全都不一样排查成本翻倍。DAO 不是不能用但它处理 .mdb 时的 Recordset 默认是表类型游标对排序和过滤的支持和 ADO 差异很大。ODBC 则多绕一层驱动管理出问题时没法直接看 Provider 层的错误信息。对于向其他系统导数据、做报表这类需求ADO 一套连接串通吃是最省心的选择。所以下面所有示例统一走 ADO 2.x 对象库。2.2 连接串怎么写Jet 与 ACE 的差异连接 Access 最常出问题的地方是 Provider 选错。Jet OLEDB 4.0 只能打开 Access 2003 及以前的 .mdb 文件Windows 自带不需要安装任何额外组件ACE OLEDB 12.0 由 Office 2007 以后引入能打开 .mdb 也能打开 .accdb但需要单独下载 AccessDatabaseEngine 安装。下表是三种写法的适用场景。Provider可打开文件适用场景Microsoft.Jet.OLEDB.4.0.mdbXP/Win7 老机器、无 Office 环境Microsoft.ACE.OLEDB.12.0.mdb、.accdb需要读 .accdb或 Jet 驱动被禁用时MSDASQL经 ODBC DSN 访问遗留系统必须走 DSN不推荐新写需要特别注意的是位数问题。VB6 编译出的 exe 是 32 位进程即使操作系统是 64 位 Windows也只能加载 32 位的 ACE 驱动。安装时选了默认的 64 位 AccessDatabaseEngine程序运行到 conn.Open 就会报未找到提供程序。判断方法是在命令提示符里执行cscript C:\Program Files (x86)\Common Files\Microsoft Shared\OFFICE16\ACEOLEDB.DLL这类检查或者直接用 32 位 ODBC 管理器C:\Windows\SysWOW64\odbcad32.exe看驱动列表里有没有 ACE 条目。2.3 最小连接代码与连接串参数说明Dim conn As ADODB.Connection Set conn New ADODB.Connection 连接串逐项拼好方便后续从配置文件读取 conn.ConnectionString ProviderMicrosoft.Jet.OLEDB.4.0; _ Data SourceC:\erp\data2000.mdb; _ Persist Security InfoFalse conn.Open If conn.State adStateOpen Then Debug.Print 连接成功 End If 业务处理完之后必须先 Close 再置空 conn.Close Set conn Nothing参数说明Provider指定 OLE DB 提供程序决定驱动加载路径Data Source是 mdb 文件的绝对路径注意 VB6 的当前目录不一定等于 exe 所在目录建议用App.Path \data\data2000.mdb拼绝对路径Persist Security Info置为 False避免连接串里的密码残留在内存或连接缓存中。如果 mdb 设置了数据库密码在连接串里追加Jet OLEDB:Database Password你的密码即可。这里有一个很多老工程师都会忽略的习惯只调conn.Close不写Set conn Nothing。在循环创建连接的代码里这会导致连接对象的引用计数不被清零Access 的 .ldb 锁文件迟迟不释放其他客户端写数据时出现文件正在使用的假象。关闭顺序严格遵守 Close 再置空是连接释放的最小规范。3. 用 Recordset 在 VB6 里做增删改查游标、锁与参数化3.1 游标类型和锁类型怎么搭配Recordset 是 ADO 操作 Access 的核心对象。打开一个 Recordset 时要同时指定游标类型和锁类型这两个参数决定数据是快照还是实时、能不能更新、更新时锁粒度多大。选错了最常见的现象是rs.Update 报当前记录集不支持更新或者遍历数据时速度奇慢。游标类型行为特征典型场景adOpenForwardOnly只能向前移动速度最快只读报表、批量导出adOpenKeyset能看到其他会话的更新看不到新增界面增删改查的默认选择adOpenStatic静态快照不感知任何变化小数据量滚动浏览adOpenDynamic完全实时开销最大Access 场景基本不用锁类型建议与游标配套只读遍历用adLockReadOnly单条编辑用adLockOptimistic批量提交用adLockBatchOptimistic。adLockPessimistic在 Access 文件模式下会导致记录长期被锁多人系统里慎用。3.2 查询遍历的标准模板Dim rs As ADODB.Recordset Set rs New ADODB.Recordset 打开一个只读、可向前遍历的结果集 rs.Open SELECT OrderID, Amount FROM Orders WHERE CustID1001, _ conn, adOpenForwardOnly, adLockReadOnly Do While Not rs.EOF Debug.Print rs.Fields(OrderID).Value - rs.Fields(Amount).Value rs.MoveNext Loop rs.Close Set rs Nothing逻辑说明EOF是判断记录集末尾的标配属性每处理完一条记录必须MoveNext否则死循环Fields(OrderID).Value按列名取值比Fields(0)可读性好也不怕 SELECT 语句调整列顺序。查询条件里如果有变量最稳妥的是走参数化见 3.4。3.3 增删改的三种路径与选择依据 方式一用 Connection.Execute 执行动作 SQL conn.Execute INSERT INTO Orders(CustID, Amount, OrderDate) _ VALUES(1001, 88.5, #2025-06-01#) 方式二用 Recordset 的 AddNew / Update Dim rsEdit As ADODB.Recordset Set rsEdit New ADODB.Recordset rsEdit.Open SELECT * FROM Orders WHERE 10, conn, _ adOpenKeyset, adLockOptimistic rsEdit.AddNew rsEdit.Fields(CustID).Value 1001 rsEdit.Fields(Amount).Value 88.5 rsEdit.Fields(OrderDate).Value Date rsEdit.Update rsEdit.Close Set rsEdit Nothing方式一适合批量初始化、不需要回读数据的场景执行快但拿不到新生成的自增编号方式二适合界面表单提交可以先 AddNew 再逐字段赋值且WHERE 10只建空结构不拖数据。注意 Access 的日期字面量必须用#包裹字符串用单引号直接拼 SQL 时字符串里的单引号要写成两个单引号转义否则一遇到客户姓名里带就报语法错误。3.4 参数化查询防注入也是防引号爆炸网上搜access 注入能看到大量针对老系统的攻击脚本原理就是拼接 SQL 时把恶意条件带进 WHERE。VB6 里最稳的防线是 Command 对象的参数化查询把值作为参数传给 Jet 引擎而不是拼进 SQL 字符串。Dim cmd As ADODB.Command Set cmd New ADODB.Command cmd.ActiveConnection conn cmd.CommandText SELECT * FROM Users WHERE UserName? AND PassWord? Dim p1 As ADODB.Parameter Set p1 cmd.CreateParameter(u, adVarWChar, adParamInput, 50, txtUser.Text) cmd.Parameters.Append p1 Dim p2 As ADODB.Parameter Set p2 cmd.CreateParameter(p, adVarWChar, adParamInput, 50, txtPass.Text) cmd.Parameters.Append p2 Dim rs As ADODB.Recordset Set rs cmd.Execute逻辑说明Jet 4.0 的 SQL 用?作占位符CreateParameter的四个参数分别指定名称、类型、方向、长度adVarWChar对应 Access 的文本类型长度必须不小于表结构里的字段长度否则参数值会被截断。参数化同时解决了引号转义的老大难问题——值里的单引号、百分号都会被当作普通字符处理。接手旧项目时不要只给登录查询打补丁凡是接受用户输入后拼 SQL 的地方统一换成这个写法。4. DataGrid 绑定 Access 数据ADODC 与代码绑定的实操配置4.1 拖控件方式ADODC 加 DataGrid在 VB6 开发环境里先确认装了 VB6 SP6 的 Common Controls菜单工程—部件勾选 Microsoft ADO Data Control 6.0SP6和 Microsoft DataGrid Control 6.0SP6工具箱里才会出现 ADODC 和 DataGrid 两个控件。这是老项目里出现频率最高的搭配但很多新手把连接串填进 ADODC 后界面却一片空白。控件属性配置值Adodc1ConnectionStringOLEDB 连接串可点生成向导Adodc1RecordSourceSELECT 语句CommandType 选 adCmdTextAdodc1Refresh配置后必须调用一次DataGrid1DataSource选 Adodc1关键的坑是顺序先配置并测试 ADODC再把 DataGrid 的 DataSource 指向 ADODC否则 DataGrid 会缓存一个空数据源。ADODC 配置完成后运行前记得把 DataGrid 的AllowUpdate设为 True否则界面能看不能改。这种方式适合快速原型缺点是连接串和 SQL 都写在控件属性里发布后不好维护。4.2 代码绑定运行时赋值与刷新时机正式项目我更建议代码绑定连接串统一从 INI 或注册表读取SQL 写在业务模块里。核心逻辑是先打开 Recordset再赋给 DataGrid 的 DataSource。Dim rs As ADODB.Recordset Set rs New ADODB.Recordset 客户端游标是 DataGrid 正常显示的前提 rs.CursorLocation adUseClient rs.Open SELECT PartID, PartName, Qty FROM Parts ORDER BY PartID, _ conn, adOpenStatic, adLockBatchOptimistic Set DataGrid1.DataSource rs参数说明CursorLocation adUseClient很关键DataGrid 依赖客户端游标做排序和分页显示adOpenStatic提供快照适合纯展示adLockBatchOptimistic为后面的批量提交做准备。绑定之后不要再对 rs 执行 Close否则 DataGrid 立即失去数据源。刷新数据时不要重新绑定直接调rs.Requery再DataGrid1.Refresh。4.3 绑定状态下增删改UpdateBatch 才是真保存DataGrid 里直接编辑单元格改动只发生在客户端游标内存中并没有写回 Access。这是VB6Access 数据库操作里最常被误会的点看起来改了、也停在界面上了关窗体重开数据没变。原因就是没有调用批量提交。 在保存按钮点击事件里统一提交 Adodc1.Recordset.UpdateBatch adAffectAll Adodc1.RefreshUpdateBatch的参数有三个常用值adAffectCurrent只提交当前行adAffectGroup提交满足当前 Filter 的行adAffectAll提交全部。提交失败时游标里会产生字段级错误轮询rs.Fields(i).Status可以定位到具体哪一行哪一列冲突。如果程序里同时用了 DataGrid 编辑和 SQL 更新两条路径切记不要混用——界面改了没 UpdateBatch这边 Execute 又按旧值去更新数据就被覆盖了。5. Access 并发场景的事务、锁与批量写入边界5.1 显式事务三行代码保证多表操作一致性Access 文件的并发能力远弱于 SQL Server但事务机制仍然可靠。凡是涉及多表联动写入的操作——比如出库时同时扣库存和写流水——必须包在显式事务里否则中间任何一条失败库存下去了流水没记录对账永远对不平。conn.BeginTrans On Error GoTo ErrHandler conn.Execute UPDATE Stock SET Qty Qty - 1 WHERE PartIDA001 conn.Execute INSERT INTO OutLog(PartID, Qty, OutDate) VALUES(A001, 1, Date()) conn.CommitTrans Exit Sub ErrHandler: conn.RollbackTrans MsgBox 操作失败已回滚 Err.Description逻辑说明BeginTrans之后的所有写操作先进入事务日志CommitTrans才真正落库任一步出错跳转后由RollbackTrans撤销全部改动。注意事务开始后那条连接上不能再执行会影响游标的操作比如同时打开多个可更新 Recordset 改数据事务期间连接占用的锁要到提交或回滚才释放所以事务体越小越好。5.2 锁等待与命令超时的参数边界Access 通过 .ldb 文件协调记录锁两个会话同时改同一条记录时后到的一方会按延迟时间重试。老系统里常见的操作被锁定报错多半是这几个参数没调过。参数默认值作用ConnectionTimeout15 秒建立连接的最长等待时间CommandTimeout30 秒单条命令的执行超时Jet OLEDB:Lock Delay100 毫秒两次抢锁尝试的间隔Jet OLEDB:Lock Retry5 次抢锁的总重试次数在代码里修改的写法是conn.ConnectionTimeout 30 conn.CommandTimeout 60 conn.Properties(Jet OLEDB:Lock Retry) 20 conn.Properties(Jet OLEDB:Lock Delay) 50参数说明Lock Retry调大适合锁冲突频繁但单次持有时间很短的场景Lock Delay调小会加重竞争调大则用户等待感明显。经验值是从默认的 100 毫秒降到 50 毫秒、重试从 5 次加到 20 次配合查询用只读游标、进入编辑才开可更新游标的方式能把锁持有时间压到最低。Access 不适合超过 10 到 20 个并发写客户端这是文件型数据库的物理边界靠调参数只能缓解不能根治。5.3 批量写入循环 Execute 与 UpdateBatch 的取舍向 Access 写入上千行数据时逐条conn.Execute是最慢的写法因为每条 SQL 都要经过字符串拼接、解析、执行三步。更快的做法是客户端游标批量模式所有 AddNew 都发生在内存里最后一次性提交。Dim rs As ADODB.Recordset Set rs New ADODB.Recordset rs.CursorLocation adUseClient rs.Open SELECT * FROM Journal, conn, adOpenStatic, adLockBatchOptimistic For i 1 To 1000 rs.AddNew rs.Fields(EntryID).Value i rs.Fields(Amount).Value i * 10 rs.Update 此时只更新客户端内存 Next i rs.UpdateBatch adAffectAll说明在adLockBatchOptimistic模式下每次rs.Update只是把改动标记在客户端缓存里UpdateBatch才向 Access 发起真正的写操作。实测 1000 行的写入批量模式比逐条 Execute 快一个数量级原因就是省掉了 1000 次 SQL 解析。批量提交的代价是失败定位困难所以提交前要做好数据校验提交后要检查rs.Filter adFilterAffectedRecords是否有失败记录。5.4 写前先看索引与库文件状态批量写入之前先确认 WHERE 条件和 ORDER BY 涉及的列上有索引Access 没有索引的筛选就是全表扫描数据量过万后速度断崖式下跌。另外 Access 删除记录不会自动回收空间频繁增删后文件碎片化严重查询变慢甚至报数据库无法打开。常规做法是定期在无人使用时段用菜单里的压缩和修复数据库处理一次压缩前必须确保所有连接都已关闭。这条对老系统尤其重要很多越用越慢的问题根源不在代码而在 mdb 文件本身。6. 一个收尾技巧VB6 打印预览 Access 数据时避开空白页6.1 DataReport 的最小绑定流程VB6 打印预览 Access 数据最常见的就是 DataReport 加 DataEnvironment。先在工程里添加 DataEnvironment 设计器建一个 Connection 指向第 2 章那条连接串再建一个 CommandSQL 写 SELECT 查询然后添加 DataReport把 DataSource 设为该 DataEnvironmentDataMember 选 Command 名最后在设计器里把字段从 Command 树拖到细节区。按钮事件里写两行If conn.State adStateOpen Then conn.Open DataReport1.Show vbModal逻辑说明DataReport 的数据源在 Show 时才取数所以调用前必须保证连接是打开状态vbModal让预览窗体独占避免用户切回主窗体又触发一次报表取数。6.2 空白页和乱码的三个高频原因第一个原因是纸张尺寸。DataReport 设计器默认是 Letter 纸国内要手动改成 A4否则右侧留白会被当成第二个页面打印预览每页后面都跟一张空白页。第二个原因是细节区高度设置过大报表每个 Section 的高度总和超过页面可打印区域必然强制分页。第三个是中文字体VB6 报表控件默认的西文字体在中文系统上显示成方块把相关控件的 Font.Charset 设为 134GB2312后重新预览即可解决。排查这类问题有个效率技巧在 Show 之前用代码核对字段绑定DataReport1.Sections(1).Controls(Text1).DataField PartName比反复开预览窗口翻页找错快得多。字段名对不上时控件显示的是空值而不是报错这是报表类问题里最隐蔽的一种。本文还有配套的精品资源点击获取
返回列表