
简介这份课程设计报告面向信息系统分析与设计相关专业的学生与自学者围绕连锁超市进销存管理信息系统的完整开发流程展开可用于课程设计参考、答辩准备或系统分析设计方法的实战学习。压缩包内共1个doc文档约1.01MB内容涵盖设计背景、技术可行性分析、系统分析、系统设计、系统实施等章节并配有总体用例图、业务流程活动图、序列图、状态图、类图及数据库需求与结构设计等图示说明。报告还涉及代码设计、输入输出设计、系统规格制订、体系结构及物理配置方案并推荐采用SQL Server 2000数据库、VB 6.0前端工具与ADO编程模型附有登录、商品类型、商品信息、进货、销售等典型窗体设计说明。目前已有66人学习适合需要完整进销存系统设计思路与文档范例的读者参考借鉴。1. 连锁超市进销存系统从课程设计到能跑通的桌面应用连锁超市的进销存管理信息系统是《信息系统分析与设计》课程设计里出现频率最高的题目之一。它看起来简单——进货、销售、库存三张表但真正动手做的时候你会发现要处理的问题远比想象中多多门店库存怎么同步、商品条码怎么设计主键、销售出库时如何保证库存不超卖、报表怎么按时间段聚合。这套系统本质上是一个典型的 C/S 架构桌面应用前端用 VB 做界面和业务逻辑后端用 SQL Server 存数据中间通过 ADO 连接。选这个组合不是因为它先进而是因为它足够成熟、资料足够多、在课程设计的时间窗口内能真正跑起来。适合谁适合正在做课程设计、需要一套完整可演示系统、并且希望理解进销存核心业务逻辑的读者。下面我会按实际开发顺序把从环境搭建到业务实现再到调试排错的完整路径拆开讲。2. 环境搭建与数据库设计先把地基打牢2.1 SQL Server 与 VB 的版本选择课程设计最怕的就是环境装不上。SQL Server 的版本选择上我一般推荐 SQL Server 2019 Express 或 SQL Server 2022 Express这两个版本在 Windows 10/11 上安装成功率最高而且 Express 版本免费、体积小、足够支撑课程设计的数据量。如果你用的是 SQL Server 2008 R2注意它和 SSMS 2022 的兼容性问题——SSMS 2022 可以连接 2008 R2 实例但某些新特性不可用课程设计场景下问题不大。VB 方面用 Visual Basic 6.0 还是 VB.NET课程设计报告里写 VB 的大概率是 VB6因为它的 ADO 控件拖拽式开发最省事。但 VB6 在 Win10/11 上安装需要处理兼容性问题建议用 VB6 精简版或者直接上 VB.NETVisual Studio 2019/2022 社区版自带后者对 SQL Server 的连接支持更好而且不用担心 16 位安装程序的问题。安装 SQL Server 时有一个高频翻车点实例配置。默认实例名是 MSSQLSERVER如果你之前装过其他版本可能会冲突。建议用命名实例比如SQLEXPRESS或自定义SUPERMARKET。安装完成后务必在 SQL Server 配置管理器里把 TCP/IP 协议启用端口保持默认 1433否则 VB 端连接会报「未找到服务器」或「连接超时」。另外SQL Server Browser 服务也要启动不然命名实例无法被客户端发现。2.2 进销存核心表结构设计进销存系统的数据库设计核心是五张表商品表、供应商表、进货表、销售表、库存表。下面是我在实际课程设计中反复打磨过的建表脚本字段类型和约束都经过验证可以直接抄。-- 商品表存储商品基础信息 CREATE TABLE Product ( ProductID VARCHAR(20) PRIMARY KEY, -- 商品条码主键 ProductName NVARCHAR(100) NOT NULL, -- 商品名称 Category NVARCHAR(50) NOT NULL, -- 商品类别 Unit NVARCHAR(10) DEFAULT 件, -- 计量单位 PurchasePrice DECIMAL(10,2) NOT NULL, -- 进货单价 SalePrice DECIMAL(10,2) NOT NULL, -- 销售单价 SupplierID VARCHAR(20) NULL, -- 供应商编号外键 CreateTime DATETIME DEFAULT GETDATE() -- 建档时间 ); -- 供应商表 CREATE TABLE Supplier ( SupplierID VARCHAR(20) PRIMARY KEY, -- 供应商编号 SupplierName NVARCHAR(100) NOT NULL, -- 供应商名称 ContactPerson NVARCHAR(50) NULL, -- 联系人 Phone VARCHAR(20) NULL, -- 联系电话 Address NVARCHAR(200) NULL -- 地址 ); -- 进货表主表 明细表结构这里简化为单表 CREATE TABLE Purchase ( PurchaseID INT IDENTITY(1,1) PRIMARY KEY, -- 自增主键 ProductID VARCHAR(20) NOT NULL, -- 商品条码 SupplierID VARCHAR(20) NOT NULL, -- 供应商编号 Quantity INT NOT NULL, -- 进货数量 UnitPrice DECIMAL(10,2) NOT NULL, -- 进货单价 TotalAmount DECIMAL(12,2) NOT NULL, -- 总金额 PurchaseDate DATETIME DEFAULT GETDATE(), -- 进货日期 Operator NVARCHAR(50) NULL -- 操作员 ); -- 销售表 CREATE TABLE Sale ( SaleID INT IDENTITY(1,1) PRIMARY KEY, -- 自增主键 ProductID VARCHAR(20) NOT NULL, -- 商品条码 Quantity INT NOT NULL, -- 销售数量 UnitPrice DECIMAL(10,2) NOT NULL, -- 销售单价 TotalAmount DECIMAL(12,2) NOT NULL, -- 总金额 SaleDate DATETIME DEFAULT GETDATE(), -- 销售日期 Operator NVARCHAR(50) NULL -- 收银员 ); -- 库存表实时库存通过触发器或业务逻辑维护 CREATE TABLE Inventory ( ProductID VARCHAR(20) PRIMARY KEY, -- 商品条码 StockQuantity INT DEFAULT 0, -- 当前库存数量 LastUpdate DATETIME DEFAULT GETDATE() -- 最后更新时间 );这段脚本的逻辑说明Product 表用商品条码做主键是因为超市场景下条码是唯一标识比自增 ID 更贴近实际。Purchase 和 Sale 表都用了 IDENTITY 自增主键因为同一商品可以多次进货和销售需要流水记录。Inventory 表单独存库存而不是每次从进货和销售表里算是为了查询性能——收银时不可能去聚合全表。参数方面DECIMAL(10,2) 表示最多 10 位数字、2 位小数足够表示万元级单价NVARCHAR 用于中文名称避免乱码。注意如果你用 SQL Server 2008 R2GETDATE()和IDENTITY都支持但NVARCHAR(MAX)在旧版本中性能较差课程设计数据量小可以忽略。2.3 VB 端 ADO 连接字符串与模块封装VB 连接 SQL Server 的核心是 ADO 的 Connection 对象。很多同学把连接字符串写死在每个窗体里改一次数据库就要改十几个地方这是血泪教训。正确做法是写一个公共模块把连接字符串和常用操作封装起来。 Module1.bas - 公共数据库模块 Public conn As ADODB.Connection Public rs As ADODB.Recordset 初始化连接 Public Sub InitDB() Set conn New ADODB.Connection 连接字符串根据实际实例名和数据库名修改 conn.ConnectionString ProviderSQLOLEDB.1; _ Persist Security InfoFalse; _ User IDsa; _ Password你的密码; _ Initial CatalogSupermarketDB; _ Data Source.\SQLEXPRESS On Error GoTo ErrHandler conn.Open Exit Sub ErrHandler: MsgBox 数据库连接失败 Err.Description, vbCritical End Sub 执行查询返回 Recordset Public Function QuerySQL(sql As String) As ADODB.Recordset Set rs New ADODB.Recordset rs.Open sql, conn, adOpenStatic, adLockReadOnly Set QuerySQL rs End Function 执行增删改 Public Sub ExecSQL(sql As String) On Error GoTo ErrHandler conn.Execute sql Exit Sub ErrHandler: MsgBox 操作失败 Err.Description, vbCritical End Sub逻辑说明InitDB在程序启动时调用一次建立全局连接。QuerySQL返回只读记录集适合填充表格控件。ExecSQL用于 INSERT、UPDATE、DELETE。参数方面Data Source.\SQLEXPRESS中的点表示本机反斜杠后是实例名如果你用的是默认实例直接写Data Source(local)或Data Source127.0.0.1。User IDsa是超级管理员课程设计图省事可以用但生产环境绝对不要。连接字符串里的ProviderSQLOLEDB.1是 SQL Server 的 OLE DB 提供程序Win10 以上系统自带不需要额外安装。3. 进货、销售与库存联动业务逻辑怎么写才不崩3.1 进货入库的完整流程与代码实现进货业务的核心动作是录入进货单 → 更新库存 → 记录流水。这三个动作必须在一个事务里完成否则会出现「进货记录写了但库存没加」的脏数据。VB6 里用 ADO 的事务控制代码如下 进货入库按钮点击事件 Private Sub cmdPurchase_Click() Dim strProductID As String Dim intQty As Integer Dim dblPrice As Double Dim strSupplierID As String strProductID Trim(txtProductID.Text) intQty Val(txtQuantity.Text) dblPrice Val(txtUnitPrice.Text) strSupplierID Trim(txtSupplierID.Text) 基础校验 If strProductID Or intQty 0 Then MsgBox 商品条码不能为空数量必须大于0, vbExclamation Exit Sub End If On Error GoTo ErrHandler conn.BeginTrans 开启事务 1. 插入进货记录 Dim sql As String sql INSERT INTO Purchase (ProductID, SupplierID, Quantity, UnitPrice, TotalAmount, Operator) _ VALUES ( strProductID , strSupplierID , intQty , dblPrice , _ (intQty * dblPrice) , admin) conn.Execute sql 2. 更新库存如果库存记录不存在则插入存在则累加 sql IF EXISTS (SELECT 1 FROM Inventory WHERE ProductID strProductID ) _ UPDATE Inventory SET StockQuantity StockQuantity intQty , LastUpdate GETDATE() _ WHERE ProductID strProductID _ ELSE _ INSERT INTO Inventory (ProductID, StockQuantity) VALUES ( strProductID , intQty ) conn.Execute sql conn.CommitTrans 提交事务 MsgBox 进货入库成功, vbInformation Exit Sub ErrHandler: conn.RollbackTrans 回滚事务 MsgBox 进货失败 Err.Description, vbCritical End Sub逻辑说明BeginTrans和CommitTrans之间的所有操作要么全成功要么全回滚。库存更新用了IF EXISTS判断这是 SQL Server 的 T-SQL 语法避免了先查再插的两次网络往返。参数方面intQty * dblPrice在 VB 里直接算总金额注意 VB 的Val函数会把空字符串转成 0所以校验要放在前面。Operator字段硬编码了admin实际项目中应该从登录信息里取。3.2 销售出库与库存扣减的防超卖处理销售出库比进货多一个关键约束库存不能为负。如果两个收银员同时卖同一件商品一个查库存是 1另一个也查是 1两人都卖库存就变成 -1 了。课程设计里虽然并发场景少但答辩时老师很可能会问这个问题。解决方案是在 UPDATE 语句里加条件 销售出库按钮点击事件 Private Sub cmdSale_Click() Dim strProductID As String Dim intQty As Integer Dim dblPrice As Double strProductID Trim(txtSaleProductID.Text) intQty Val(txtSaleQuantity.Text) dblPrice Val(txtSalePrice.Text) If strProductID Or intQty 0 Then MsgBox 商品条码不能为空数量必须大于0, vbExclamation Exit Sub End If On Error GoTo ErrHandler conn.BeginTrans 1. 检查库存是否充足带锁查询 Dim rsCheck As ADODB.Recordset Set rsCheck conn.Execute(SELECT StockQuantity FROM Inventory WITH (UPDLOCK) WHERE ProductID strProductID ) If rsCheck.EOF Then MsgBox 该商品无库存记录, vbExclamation conn.RollbackTrans Exit Sub End If If rsCheck.Fields(StockQuantity).Value intQty Then MsgBox 库存不足当前库存 rsCheck.Fields(StockQuantity).Value, vbExclamation conn.RollbackTrans Exit Sub End If 2. 插入销售记录 Dim sql As String sql INSERT INTO Sale (ProductID, Quantity, UnitPrice, TotalAmount, Operator) _ VALUES ( strProductID , intQty , dblPrice , _ (intQty * dblPrice) , admin) conn.Execute sql 3. 扣减库存带条件更新防止并发超卖 sql UPDATE Inventory SET StockQuantity StockQuantity - intQty , LastUpdate GETDATE() _ WHERE ProductID strProductID AND StockQuantity intQty conn.Execute sql 检查是否真的更新了影响行数为0说明库存被其他事务扣完了 If conn.Execute(SELECT ROWCOUNT).Fields(0).Value 0 Then MsgBox 库存不足销售失败, vbExclamation conn.RollbackTrans Exit Sub End If conn.CommitTrans MsgBox 销售出库成功, vbInformation Exit Sub ErrHandler: conn.RollbackTrans MsgBox 销售失败 Err.Description, vbCritical End Sub逻辑说明WITH (UPDLOCK)是 SQL Server 的锁提示在查询时对行加更新锁防止其他事务同时修改。ROWCOUNT返回上一条语句影响的行数如果为 0 说明 UPDATE 的条件不满足即库存不够。参数方面UPDLOCK只在事务内有效所以必须放在BeginTrans之后。注意 VB 里conn.Execute返回的是 Recordset取ROWCOUNT要用.Fields(0).Value。3.3 库存查询与低库存预警库存查询看起来简单但课程设计里经常被要求做「低库存预警」即库存低于某个阈值时高亮显示。实现方式有两种一种是在 VB 里遍历 Recordset 判断另一种是直接在 SQL 里算。推荐后者因为数据量大了以后 VB 遍历会卡。-- 查询所有商品库存并标记是否低库存阈值设为10 SELECT p.ProductID, p.ProductName, p.Category, ISNULL(i.StockQuantity, 0) AS StockQuantity, CASE WHEN ISNULL(i.StockQuantity, 0) 10 THEN 低库存 ELSE 正常 END AS StockStatus FROM Product p LEFT JOIN Inventory i ON p.ProductID i.ProductID ORDER BY StockQuantity ASC逻辑说明LEFT JOIN保证没有库存记录的商品也能显示出来ISNULL把 NULL 转成 0。CASE WHEN是 SQL Server 的条件表达式直接在结果集里给出状态标记。VB 端只需要把StockStatus字段绑定到表格控件的颜色属性上即可。参数方面阈值 10 可以做成配置项存在一个单独的 Config 表里方便调整。4. 避坑与排查课程设计里最容易翻车的五个地方4.1 连接报错「未找到服务器」或「SSL 证书链不受信任」现象VB 程序启动时弹窗报错提示无法连接 SQL Server错误信息里可能包含「SSL 提供程序: 证书链是由不受信任的颁发机构颁发的」或「客户端无法建立连接」。原因SQL Server 2019/2022 默认强制加密连接而自签名证书不被客户端信任。另外TCP/IP 协议未启用或端口不对也会导致连接失败。解决在 SQL Server 配置管理器里启用 TCP/IP重启服务。然后在连接字符串里加EncryptOptional或TrustServerCertificateTrue。如果用的是 ODBC 驱动在 DSN 配置里勾选「信任服务器证书」。课程设计场景下直接关掉强制加密最省事在 SQL Server 属性 → 连接 → 勾选「允许远程连接到此服务器」并在客户端协议里禁用加密。4.2 VB6 在 Win10/11 上安装后无法运行或控件缺失现象VB6 安装完成但打开项目时提示「找不到控件」或运行时崩溃。原因VB6 是 1998 年的产品部分系统组件在 Win10/11 上注册失败尤其是 ADO 控件和 Common Dialog 控件。解决以管理员身份运行 VB6手动注册关键 DLLregsvr32 C:\Program Files (x86)\Common Files\System\ado\msado15.dll。如果还是不行改用 VB.NETVisual Studio 社区版对 Win10/11 支持完善ADO.NET 的连接方式虽然不同但课程设计报告里写 VB 并不限定必须是 VB6。4.3 中文乱码数据库存进去是问号现象VB 界面输入中文商品名保存到 SQL Server 后变成???。原因数据库字段用了VARCHAR而不是NVARCHAR或者连接字符串没有指定字符集。解决建表时所有中文字段用NVARCHAR连接字符串里加CharsetUnicode或直接用ProviderSQLOLEDB.1默认支持 Unicode。如果已经建了VARCHAR字段用ALTER TABLE改成NVARCHAR。4.4 库存更新后数据对不上事务没提交或回滚不彻底现象进货记录写入了但库存没变或者销售扣了库存但销售记录没生成。原因事务边界没控制好比如BeginTrans之后某个Execute报错但错误处理里没有RollbackTrans导致事务一直挂着。解决每个BeginTrans必须配对CommitTrans或RollbackTrans放在On Error GoTo的错误处理块里。另外VB 的 ADO 连接如果中途断开事务会自动回滚但连接池里的连接状态可能异常建议在InitDB里加conn.IsolationLevel adXactReadCommitted。4.5 报表查询超时没有索引的全表扫描现象销售报表按日期范围查询时数据量稍微大一点就卡死或超时。原因Sale表的SaleDate字段没有索引SQL Server 每次查询都全表扫描。解决给常用查询字段加索引。CREATE INDEX IX_Sale_Date ON Sale(SaleDate)CREATE INDEX IX_Purchase_Date ON Purchase(PurchaseDate)。课程设计数据量小的时候感觉不到但答辩演示时如果现场录入几百条数据没索引的查询会明显变慢。5. 报表统计与进阶技巧让课程设计多拿几分报表是课程设计的加分项。进销存系统至少要有三个报表日销售汇总、商品销售排行、库存周转率。日销售汇总用GROUP BY按日期聚合商品销售排行用ORDER BY SUM(Quantity) DESC库存周转率稍微复杂一点需要结合进货和销售数据算。-- 商品销售排行前10名 SELECT TOP 10 p.ProductName, SUM(s.Quantity) AS TotalSold, SUM(s.TotalAmount) AS TotalRevenue FROM Sale s INNER JOIN Product p ON s.ProductID p.ProductID WHERE s.SaleDate DATEADD(DAY, -30, GETDATE()) -- 最近30天 GROUP BY p.ProductName ORDER BY TotalSold DESC逻辑说明DATEADD(DAY, -30, GETDATE())算出 30 天前的日期TOP 10取前 10 条。INNER JOIN保证只统计有商品信息的销售记录。VB 端把结果绑定到 MSHFlexGrid 或 DataGrid 控件即可。进阶技巧方面我一般会加一个「一键备份数据库」的功能用 SQL Server 的BACKUP DATABASE语句在 VB 里调用ExecSQL执行。这样答辩时演示数据恢复很方便老师也会觉得考虑周全。另外登录模块不要明文存密码用PWDENCRYPT函数或者简单的 MD5 哈希虽然课程设计不要求但写进报告里是加分项。最后说一个我踩过的坑VB6 的Recordset在窗体关闭时如果不显式Close会导致内存泄漏程序跑久了越来越卡。习惯是每个QuerySQL返回的 Recordset 用完就rs.Close: Set rs Nothing。这个习惯在课程设计里可能看不出差别但工作以后写正式项目这就是专业和业余的分界线。希望帮到你。本文还有配套的精品资源点击获取