简介这份家庭理财管理系统数据库课程设计文档面向高校计算机与信息管理相关专业学生尤其是正在完成数据库课设或需要参考完整设计流程的学习者。资源以沈阳理工大学课程设计模板为框架系统呈现从需求分析、概念结构设计到逻辑结构设计与数据实施维护的全过程并给出基于VB的界面设计与关键代码帮助读者理解Access数据库在实际管理系统中的落地方法。压缩包内仅含1个doc文档约1.25MB内容涵盖E-R图、关系模式转换、用户表与银行信息表等建表过程以及登录、主界面、基本信息管理、理财信息管理、数据统计和用户管理六大模块的界面实现。文档还包含系统流程分析图、功能模块示意图与结果分析可辅助读者梳理课设报告结构、对照完成数据库设计与代码编写。目前已有180人学习适合作为数据库课程设计的参考范例与排错思路来源。1. 家庭理财管理系统数据库课设从建表到 VB 增删改查的完整落地路径很多同学拿到「家庭理财管理系统数据库课设.doc」这个题目时第一反应是去搜现成源码结果下载下来一堆跑不起来的工程或者表结构设计得根本经不起答辩老师追问。这个课设的核心其实就两件事一是用 Access 设计一套能自洽的家庭收支数据库二是用 VB 把增删改查界面接上去。它适合数据库原理、VB 程序设计这类课程的期末大作业也适合想练手 Access 加 VB 组合的初学者。热搜里「数据库增删改查」「access数据库」「VB」这几个词反复出现说明大家卡的点高度一致表建完了代码连不上能连上查询又报错。这篇就按我实际带课设的经验把从零到能演示的路径拆开讲参数怎么设、坑在哪都写清楚。2. 家庭理财数据库的表结构设计与 Access 落地2.1 为什么先定实体再画表而不是直接开 Access 建字段家庭理财管理系统的数据模型不复杂但很多同学一上来就在 Access 里建一张大表把收入、支出、账户、成员全塞进去结果查询时到处冗余答辩时被问「你这表满足第几范式」就卡住了。常见做法是先抽实体家庭成员、收支账户、收支分类、收支记录。这四个实体对应四张基础表关系是一个成员可以有多个账户一个账户属于一个成员一条收支记录关联一个账户和一个分类。这样设计的好处是账户余额可以通过收支记录汇总算出来不需要在账户表里再存一个余额字段去手动维护否则一旦漏更新就对不上账。Access 里建表时字段类型要卡死金额用「货币」类型日期用「日期/时间」备注用「长文本」主键用「自动编号」。别用「文本」存金额后面 VB 里做 SUM 汇总时会因为类型转换报错这是血泪经验。2.2 在 Access 里建四张核心表的字段清单与约束下面这张表是我一般会用的字段设计可以直接照着在 Access 设计视图里敲。注意表名和字段名尽量用英文或拼音避免 VB 里 SQL 语句拼接时中文表名带来的编码问题。表名字段名类型说明MemberMemberID自动编号主键家庭成员编号MemberMemberName短文本成员姓名MemberRelation短文本与户主关系AccountAccountID自动编号主键账户编号AccountAccountName短文本账户名如工资卡AccountMemberID数字外键关联 MemberCategoryCategoryID自动编号主键分类编号CategoryCategoryName短文本分类名如餐饮CategoryType短文本收入或支出RecordRecordID自动编号主键记录编号RecordAccountID数字外键关联 AccountRecordCategoryID数字外键关联 CategoryRecordAmount货币金额RecordRecordDate日期/时间发生日期RecordNote长文本备注建完表后在 Access 的「数据库工具」里点「关系」把外键拖到对应主键上勾选「实施参照完整性」。这一步不做后面 VB 删除账户时可能留下孤儿记录查询汇总就会多出莫名其妙的金额。2.3 用 Access 查询设计器先验证数据再写 VB 代码在写 VB 之前我强烈建议先在 Access 里用查询设计器把几个核心查询跑通按成员汇总收支、按分类汇总支出、按月统计结余。这样做的好处是SQL 逻辑在 Access 里验证过了搬到 VB 里只是换一个执行入口出错概率大幅降低。比如「按成员汇总收支」这个查询在 Access 里可以这样写SELECT m.MemberName, SUM(IIf(c.Type收入, r.Amount, 0)) AS TotalIncome, SUM(IIf(c.Type支出, r.Amount, 0)) AS TotalExpense FROM ((Member m INNER JOIN Account a ON m.MemberID a.MemberID) INNER JOIN Record r ON a.AccountID r.AccountID) INNER JOIN Category c ON r.CategoryID c.CategoryID GROUP BY m.MemberName;这段 SQL 的逻辑是从 Member 出发经 Account 和 Record 两张表连到 Category用 IIf 把收入和支出分开累加。参数说明IIf是 Access 特有的条件函数VB 里不能直接用但可以在 Access 查询里先验证结果对不对。如果这里汇总出来的数字和手工算的对不上先检查 Record 表里有没有 AccountID 或 CategoryID 为空的记录外键约束没生效时很容易出现。3. VB 连接 Access 数据库从 ADO 控件到连接字符串3.1 选 ADO 还是 DAO课设场景下怎么定VB6 连 Access 有两条路DAO 和 ADO。现在课设环境大多是 VB6 加 Access 2003 或 2007 格式我一般推荐用 ADO因为 ADO 的 Connection 和 Recordset 对象在后续做增删改查时更统一而且连接字符串写起来直观。DAO 虽然对 Access 原生支持好但很多新系统已经不用了答辩时老师如果问「你这用的什么数据访问技术」说 ADO 更稳妥。需要提前确认一件事你的 Access 文件是.mdb还是.accdb。.mdb用Microsoft.Jet.OLEDB.4.0提供程序.accdb用Microsoft.ACE.OLEDB.12.0。后者需要装 Access Database Engine如果目标机器上没装程序会报「未找到提供程序」。课设演示如果换机器这一点要提前试。3.2 一个可复用的 VB 数据库连接模块不要在每個窗体里重复写连接代码建一个标准模块modDB.bas把连接和通用查询封装进去。下面是我常用的写法 modDB.bas - 数据库连接与通用操作模块 Option Explicit Public conn As ADODB.Connection 初始化连接Access 文件放在程序目录下 Public Function OpenDB() As Boolean On Error GoTo ErrHandler Set conn New ADODB.Connection 如果是 .mdb 文件用 Jet 提供程序 conn.ConnectionString ProviderMicrosoft.Jet.OLEDB.4.0; _ Data Source App.Path \FamilyMoney.mdb; conn.Open OpenDB True Exit Function ErrHandler: MsgBox 数据库连接失败 Err.Description, vbCritical OpenDB False End Function 执行增删改返回受影响行数 Public Function ExecSQL(ByVal sql As String) As Long Dim cmd As ADODB.Command Set cmd New ADODB.Command cmd.ActiveConnection conn cmd.CommandText sql cmd.Execute ExecSQL cmd.Execute End Function逻辑说明OpenDB负责建立全局连接App.Path保证数据库文件和 exe 在同一目录换机器时只要把 mdb 一起拷过去就行。ExecSQL用 Command 对象执行 SQL比直接conn.Execute更规范也方便后续改成参数化查询。参数说明连接字符串里的Data Source必须是完整路径如果数据库放在子目录改成App.Path \data\FamilyMoney.mdb。注意On Error GoTo是 VB6 的错误处理方式别写成 .NET 的 Try Catch。3.3 窗体加载时绑定数据到 MSHFlexGrid查询结果显示课设里最常用的是 MSHFlexGrid 控件。在窗体 Load 事件里调用查询把 Recordset 赋给 Grid 的 DataSource。这里有个坑如果 Recordset 是断开连接后赋值的Grid 可能显示空白。稳妥做法是保持连接打开或者用Set Grid.DataSource rs之前先rs.Open。 frmRecord.frm - 收支记录列表加载 Private Sub Form_Load() Dim rs As ADODB.Recordset If Not OpenDB() Then Exit Sub Set rs New ADODB.Recordset rs.Open SELECT r.RecordID, a.AccountName, c.CategoryName, _ r.Amount, r.RecordDate, r.Note _ FROM (Record r INNER JOIN Account a ON r.AccountIDa.AccountID) _ INNER JOIN Category c ON r.CategoryIDc.CategoryID _ ORDER BY r.RecordDate DESC, conn, adOpenStatic, adLockReadOnly Set MSHFlexGrid1.DataSource rs MSHFlexGrid1.ColWidths(0) 0 隐藏 RecordID 列 End Sub这段代码把三张表连起来查按日期倒序显示。adOpenStatic表示静态游标适合只读展示adLockReadOnly避免误改。ColWidths(0)0是把主键列藏起来界面上不显示但后续删除要用到。如果 Grid 里中文显示乱码检查 Access 表的字段是不是「短文本」且没有设成 Unicode 压缩一般默认没问题。4. 增删改查四个功能的 VB 实现与参数校验4.1 新增记录用参数化 SQL 防注入和类型错误新增收支记录时很多同学直接用字符串拼接 SQL金额里带个单引号就崩日期格式不对也崩。正确做法是用 ADO 的 Parameter 对象或者至少对输入做校验。下面用参数化方式写新增 新增一条收支记录 Public Function AddRecord(ByVal accountID As Long, ByVal categoryID As Long, _ ByVal amount As Currency, ByVal rDate As Date, _ ByVal note As String) As Boolean On Error GoTo ErrHandler Dim cmd As ADODB.Command Set cmd New ADODB.Command cmd.ActiveConnection conn cmd.CommandText INSERT INTO Record (AccountID, CategoryID, Amount, RecordDate, Note) _ VALUES (?, ?, ?, ?, ?) cmd.Parameters.Append cmd.CreateParameter(p1, adInteger, adParamInput, , accountID) cmd.Parameters.Append cmd.CreateParameter(p2, adInteger, adParamInput, , categoryID) cmd.Parameters.Append cmd.CreateParameter(p3, adCurrency, adParamInput, , amount) cmd.Parameters.Append cmd.CreateParameter(p4, adDate, adParamInput, , rDate) cmd.Parameters.Append cmd.CreateParameter(p5, adVarWChar, adParamInput, 255, note) cmd.Execute AddRecord True Exit Function ErrHandler: MsgBox 新增失败 Err.Description, vbExclamation AddRecord False End Function逻辑说明?是 Access 参数占位符按顺序对应后面的 CreateParameter。参数类型要匹配金额用adCurrency日期用adDate备注用adVarWChar并指定长度 255。这样即使用户在备注里输入单引号也不会破坏 SQL 结构。参数说明adParamInput表示输入参数最后一个参数是实际值。如果新增后 Grid 没刷新记得重新调用查询加载。4.2 删除与修改先定位主键再执行更新删除和修改的前提是拿到当前选中行的主键。MSHFlexGrid 里虽然隐藏了 RecordID 列但可以通过TextMatrix读取。删除前一定要弹确认框这是课设演示的加分项也是防止误操作的基本习惯。 删除当前选中的记录 Private Sub cmdDelete_Click() Dim rid As Long If MSHFlexGrid1.Row 0 Then MsgBox 请先选中一行记录, vbInformation Exit Sub End If rid Val(MSHFlexGrid1.TextMatrix(MSHFlexGrid1.Row, 0)) If MsgBox(确定删除记录 rid 吗, vbYesNo vbQuestion) vbNo Then Exit Sub If ExecSQL(DELETE FROM Record WHERE RecordID rid) 0 Then MsgBox 删除成功 Call Form_Load 刷新列表 End If End Sub逻辑说明TextMatrix(Row, 0)取的是第 0 列也就是隐藏的 RecordID。Val做一次数值转换防止空值。删除后重新调用 Form_Load 刷新数据。参数说明ExecSQL返回受影响行数大于 0 表示删掉了记录。注意如果表之间设了级联删除删账户会连带删记录课设里一般不建议开级联手动控制更安全。4.3 查询与汇总用 DataGrid 还是 MSHFlexGrid 展示结果查询功能分两种明细查询和汇总查询。明细用 MSHFlexGrid 展示原始记录汇总可以用 DataGrid 或者直接拼字符串显示在 Label 上。我一般把汇总做成一个独立窗体用几个 Label 显示总收入、总支出、结余数据来源就是第 2 章验证过的汇总 SQL。 按成员汇总显示 Private Sub cmdSummary_Click() Dim rs As ADODB.Recordset Set rs New ADODB.Recordset rs.Open SELECT m.MemberName, _ SUM(IIf(c.Type收入, r.Amount, 0)) AS Income, _ SUM(IIf(c.Type支出, r.Amount, 0)) AS Expense _ FROM ((Member m INNER JOIN Account a ON m.MemberIDa.MemberID) _ INNER JOIN Record r ON a.AccountIDr.AccountID) _ INNER JOIN Category c ON r.CategoryIDc.CategoryID _ GROUP BY m.MemberName, conn, adOpenStatic, adLockReadOnly Set MSHFlexGrid2.DataSource rs End Sub这段和 Access 里验证的 SQL 基本一致只是换到 VB 里执行。参数说明IIf在 Access SQL 里可用但如果换成 SQL Server 就要改成CASE WHEN。课设用 Access 没问题。如果汇总结果为空检查 Record 表里是否有数据以及 Category 表的 Type 字段值是否严格等于「收入」或「支出」多一个空格都会导致 IIf 判断失败。5. 课设避坑连接失败、类型不匹配与演示翻车排查5.1 报「未找到提供程序」或「不可识别的数据库格式」现象程序在本机跑得好好的拷到同学电脑或答辩教室的机器上一打开就弹「未找到提供程序 Microsoft.Jet.OLEDB.4.0」或「不可识别的数据库格式」。原因目标机器没装对应版本的 Access 数据库引擎或者你的 Access 文件是.accdb但用了 Jet 提供程序。解决如果是.mdb确认系统是 32 位 Office 环境如果是.accdb把连接字符串改成Microsoft.ACE.OLEDB.12.0并提前在目标机器上装 Access Database Engine。最稳妥的办法是课设统一用.mdb格式兼容性最好。5.2 金额汇总出现小数位异常或负数现象汇总出来的总支出比手工算的多几分钱或者结余变成负数但实际是正的。原因Amount 字段类型设成了「双精度」而不是「货币」浮点累加产生误差或者收入支出的 IIf 条件写反了。解决把 Amount 字段改成「货币」类型Access 里货币是定点数累加不会丢精度。同时检查 Category 表的 Type 值确保收入和支出的拼写完全一致建议用下拉框录入而不是手动输入。5.3 VB 里日期格式导致查询结果为空现象按日期范围查询时明明有数据却查不出来。原因VB 的 Date 类型在拼接 SQL 时默认用系统短日期格式如果系统是yyyy/m/d而 Access 里存的是yyyy-mm-dd比较就会失败。解决不要直接拼接日期字符串用参数化查询传adDate参数或者用Format(dateVar, yyyy-mm-dd)显式转换。我一般统一用参数化省去格式烦恼。5.4 删除记录后 Grid 还显示旧数据现象点了删除数据库里确实删了但 MSHFlexGrid 里那行还在。原因删除后没有重新绑定 RecordsetGrid 还持有旧的游标。解决删除成功后重新执行查询并Set Grid.DataSource rs或者调用Grid.Refresh。注意如果 Recordset 是adLockReadOnly刷新前要先关闭再重新打开。5.5 窗体卸载时连接没关导致 Access 文件被锁现象程序关闭后Access 文件旁边多了个.ldb锁文件再次打开数据库提示「文件已被占用」。原因VB 退出时没有关闭 Connection 和 Recordset。解决在Form_Unload或Sub Main退出前显式写If Not conn Is Nothing Then conn.Close并把对象设为 Nothing。课设演示时如果中途强制结束进程锁文件不会自动消失手动删掉.ldb即可。6. 让课设经得起追问用视图和事务把数据一致性做扎实课设答辩时老师最容易追问的两个点是「数据一致性怎么保证」和「有没有考虑并发」。家庭理财系统虽然单机为主但把这两点做出来课设档次会明显不一样。我的习惯是在 Access 里建一个汇总视图把第 2 章的汇总 SQL 保存成查询对象VB 里直接SELECT * FROM qryMemberSummary这样 SQL 逻辑集中在数据库层VB 代码更干净也方便答辩时展示「我用了视图」。另一个技巧是用事务包住「转账」这类多步操作。家庭理财里经常有从一个账户转到另一个账户的场景对应两条记录一条支出、一条收入。如果只成功了一条账就错了。VB 里可以用conn.BeginTrans和conn.CommitTrans包起来 账户间转账两条记录要么都成功要么都回滚 Public Function Transfer(ByVal fromAcc As Long, ByVal toAcc As Long, _ ByVal amount As Currency, ByVal cidOut As Long, _ ByVal cidIn As Long) As Boolean On Error GoTo ErrHandler conn.BeginTrans 转出记录 conn.Execute INSERT INTO Record (AccountID, CategoryID, Amount, RecordDate) _ VALUES ( fromAcc , cidOut , amount ,Now()) 转入记录 conn.Execute INSERT INTO Record (AccountID, CategoryID, Amount, RecordDate) _ VALUES ( toAcc , cidIn , amount ,Now()) conn.CommitTrans Transfer True Exit Function ErrHandler: conn.RollbackTrans MsgBox 转账失败已回滚 Err.Description, vbCritical Transfer False End Function逻辑说明BeginTrans开启事务两条 INSERT 都成功后CommitTrans提交任何一步出错跳到 ErrHandlerRollbackTrans撤销已执行的插入。参数说明fromAcc和toAcc是转出转入账户 IDcidOut和cidIn对应支出和收入分类 ID。注意 Access 的事务支持有限只对同一数据库连接有效且不能跨表级联太复杂。如果课设里不做转账这个事务思路也可以用在「批量导入记录」上保证要么全导入要么全不导入。最后说一个我自己的习惯每次改完 VB 代码先把 Access 里的表复制一份做备份再跑程序测试。课设期间我见过太多同学因为一条 DELETE 没加 WHERE 条件把整张 Record 表清空又没有备份只能重录数据。这个后悔药希望你别吃。把视图和事务用上答辩时老师问「你怎么保证数据不错」你就有东西可讲而不是只能说「我测试过了」。希望帮到你。本文还有配套的精品资源点击获取