ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

超市管理系统实训报告拆解:从C#代码到Java改造的完整路径

超市管理系统实训报告拆解:从C#代码到Java改造的完整路径

简介:《Java超市管理系统实训报告》是一份面向高校计算机相关专业学生的课程设计文档,围绕超市管理场景完整演示了从需求分析、数据库设计到系统实现与测试的全过程。报告内容涵盖系统可行性分析、E-R模型设计、数据库表结构规划,以及用户管理、商品管理、库存管理、销售记录等核心模块的实现思路,适合正在学习Java与数据库原理、需完成类似课设任务或想了解小型管理系统开发流程的读者参考。压缩包内仅含1个doc文件,文件大小约411KB,虽为文档型资源,但结构完整,包含课程设计目的、系统需求分析、技术背景、设计与实现、测试优化及结论等章节,便于直接借鉴报告框架和设计思路。目前已有5778人学习或下载,是同类实训报告中较受关注的参考材料。通过研读该报告,读者可以快速理解超市管理系统各模块间的数据关系,获得编写课程设计报告的整体脉络和细节要点,为独立开发或文档撰写提供实用支持。

1. 一份写着 Java 却全是 C# 代码的超市管理系统实训报告

打开这份《Java超市管理系统实训报告》,第一眼你会怀疑拿错了文档:课题名称写着“超市管理系统”,开发工具写的是 Eclipse,目录里列着数据库设计、功能模块实现,煞有介事。再往后翻到代码部分,画风突变——SqlDataReader、MessageBox、DataClass.MyMeans,通篇是 C# WinForms 的写法。这不是低质量拼接,而是当年课程设计里非常真实的场景:报告按 Java 课程的要求提交,实现却用了顺手的技术栈。

抛开“名不副实”这一点,这份报告的骨架其实相当完整。它把一套超市管理系统从立项到落地的所有环节都覆盖了:需求分析、可行性分析、五大功能模块(商品、人事、销售、进货、库存)、7 张数据库表、E-R 模型、建库脚本、登录验证、商品录入、库存联动。对正在做毕业设计或课程设计的同学,它是现成的“参考答案”;对想快速搭一套进销存管理系统的开发者,它的数据库设计和模块划分可以直接抄作业。这篇笔记我会把它拆开,先看它到底做了什么,再重点分析数据库和核心代码怎么落地,最后给出一条把这份“C# 芯的 Java 报告”改造成能跑通的纯 Java 项目的路径。

2. 项目定位与技术选型:叫 Java 的实训报告,代码却是 C# 风格

2.1 这份资源到底是什么:课程设计报告,不是可运行源码包

先说明一件事,避免期望管理翻车。这份资源是一份完整的课程设计报告文档,不是打包好的可执行工程。它的目录结构完全是报告体:第 1 章课程设计的目的,第 2 章需求分析,第 3 章技术背景,第 4 章总体设计,第 5 章数据库设计,第 6 章功能模块实现,第 7 章关键技术,第 8 章结论。每章都配有界面截图占位、代码片段和表结构定义,逻辑上是一份可以拿去答辩的完整文档。

这意味着你下载后不能直接编译运行,但它提供的价值不在“能跑”,而在“能照着做”。如果你需要的是一个能从零讲清楚“超市管理系统怎么设计”的范本——需求怎么分析、表怎么建、模块怎么拆、登录怎么验证、库存怎么联动——这份文档比一个能跑的玩具项目信息量大得多。我拆解这份资源的策略是:把报告里真正可复用的部分(数据库设计、模块划分、核心逻辑)提炼出来,再把缺失的部分(完整代码、依赖配置、可执行工程)按合格开发者的习惯补全。

2.2 技术栈盘点:Eclipse、SQL Server 2005 与“薛定谔”的代码

报告第 3 章写明:选用 Eclipse 作为前台开发工具,后台数据库采用 SQL Server 2005,整体设计以软件工程思想为指导思想。但在第 1 章的课程设计环境里,写的又是 Microsoft Visual Studio 2005,第 6 章的代码片段则清一色是 C# 风格。为什么会出现这种错位?我倾向于这样理解:这是一份以 Java 课程名义提交、但实际参考了 C# WinForms 教程写出来的报告,作者很可能用 C# 实现了原型,再套到 Java 课程设计的壳里交差。

这个翻车现场恰恰给了一个常见教训:课程设计的选题和技术栈必须一致。如果题目要求 Java,实现就该是 Swing 或 JavaFX 加 JDBC 加 MySQL;如果执着于 C#,那就别把报告标题写成 Java。不过站在拆解的角度,这个矛盾反而让文档有了教学价值——同一套业务设计,你能同时看到 C# 的实现方式和 Java 的改造路径。第 6 章我会给出一套完整的 Java 改造方案。现在先记住这份报告的“真实身份”:数据库设计是正经的,模块划分是正经的,代码风格是“薛定谔”的。

2.3 系统结构框架:五大模块围着“进销存”转

系统功能结构图(报告图 4-1)把系统拆成五个模块:商品信息管理、人事管理(职工与供货商)、销售管理、进货管理、库存管理。这五块合起来就是超市最核心的业务闭环:进货入库、库存沉淀、前台销售、库存扣减,再由人事管理保证谁在操作、供货商管理保证货从哪来。报告的设计目标部分明确写了四大模块,但功能结构图又扩成五大模块,商品信息管理被单独拎了出来,这也是实训报告里常见的“需求分析和总体设计各写各的”问题。

这个模块划分是相当标准的进销存结构,也是我觉得整份报告最值得参考的地方。它没有为了炫技加一堆花哨功能,而是严格贴着业务走。你把它换成“图书管理系统”“药品管理系统”,模块骨架照样成立——商品换成图书,进货换成采购,销售换成借阅,库存概念天然契合。这就是面向业务的模块划分和面向功能的模块划分的区别:前者换行业场景后依然能复用,后者换个需求就得重构。

3. 数据库设计:这份报告最值钱的部分,7 张表加视图加建库脚本

3.1 E-R 模型与表关系:一张图看清数据怎么流转

报告第 5 章给出了数据库 E-R 模型图,核心实体包括职工或用户、供货商、商品、进货、销售、库存。用文字还原这张图:职工和用户是同一拨人,StaffBill 存储职工信息,Users_Info 存登录账号;供货商向超市供货;商品从供货商处进货形成进货记录;商品卖给顾客形成销售记录;每次进货和销售都影响库存表。关系大致是:职工 1 对 N 商品(谁维护商品),供货商 1 对 N 商品,商品 1 对 N 进货,商品 1 对 N 销售。

库存表比较特殊,只有两个核心字段(商品编号与库存数量),可以理解为商品表的附属状态表,由程序在进销操作时手动维护。注意,这份报告没有用触发器或存储过程来自动更新库存,而是由业务代码手动 insert 或 update,这是后面功能实现里的一个关键信号——它决定了数据一致性要靠在代码层面做事务来保证,而报告本身并没有写事务。拆到这里你应该有感觉了:这份报告的设计意图是对的,但落地细节到处是坑。

3.2 核心表结构逐个拆:主键、外键、字段类型怎么定

7 张表按用途可以分成四类:人员类(StaffBill 职工表、Users_Info 用户登录表),商品类(Goods_Info 商品表、Sup_Info 供货商表),流水类(Buy 进货表、Sell 销售表),状态类(Stock 库存表)。各表字段定义如下表所示。

表名中文名关键字段主键/外键用途
StaffBill职工信息表staffID, name, sex, idCardstaffID 主键职工基本信息
Users_Info用户登录表loginID, passWordloginID 主键/外键登录账号密码
Goods_Info商品信息表merchID, profferID, unitCostmerchID 主键, profferID 外键商品档案
Sup_Info供货商信息表SupplierID, contactPerson, phoneSupplierID 主键供货商档案
Buy进货信息表BuyID, GoodsID, Price, DatedBuyID+GoodsID 联合主键进货流水
Sell销售信息表SellID, GoodsID, Amount, DatedSellID+GoodsID 联合主键销售流水
Stock库存信息表GoodsID, AmountGoodsID 主键/外键库存数量

以职工表 StaffBill 为例:staffID 用 char(6) 做主键、非空约束,name 用 nvarchar(8),sex 用 nchar(2),idCard 用 varchar(18),备注字段用 ntext(50) 可空。char 定长字符串做主键,在 2005 年的 SQL Server 语境下很常见——编号固定 6 位,查询快,但扩展性差,编号一旦超过 6 位就要改表结构,属于典型的课程设计够用、生产环境嫌弃的设计。

商品表 Goods_Info 更值得看:merchID 主键,profferID 外键关联供货商表,unitCost 用 money 类型而不是 int,这是数据库设计里的专业点——金额用 money,进价和售价才能保证小数精度,用 int 存金额的后果是分单位换算或四舍五入误差。流水表的设计思路是“单据加明细”,进货表 Buy 的联合主键是 BuyID 加 GoodsID,表达“一张进货单里可以包含多个商品”;销售表 Sell 同理。这种联合主键在课程设计层面够用,但生产环境通常会把主表和明细表拆成两张,避免同一商品在同一单里重复出现的约束冲突。

3.3 建库脚本与库存视图:能直接执行的 T-SQL,但有一处截断

报告 5.3 节给了三段可执行的 SQL。第一段建库,用 CREATE DATABASE 指定主数据文件和日志文件的路径、初始大小和增长方式;第二段建库存表;第三段建库存视图。先看建表这段:

CREATE TABLE Stock( GoodsID varchar(10) COLLATE Chinese_PRC_CI_AS NOT NULL, Amount int NOT NULL, PRIMARY KEY (StockID), FOREIGN KEY (GoodsID) REFERENCES tb_Goods(GoodsID) );

这里就有明显的文档问题:5.2.7 节的库存表描述里只有 GoodsID 和 Amount 两个字段,这段建表 SQL 却冒出了 StockID 主键和记录里没提的约束。StockID 作为主键意味着库存表可以有多条同商品记录,这跟“一个商品一条库存”的设计目标冲突。真要跑这段 SQL,还得先确认 tb_Goods 表存在,以及 StockID 字段是否需要补。实训报告里这种“表设计一节、建表脚本一节、代码一节”互相打架的情况非常多,照着执行大概率报错。我在第 5 章的避坑清单里会专门讲排查方法。

第三段建库存视图,逻辑是正确且可用的——把库存表和商品表 inner join,让库存报表直接展示商品名称而不是光秃秃的编号:

create view v_StockSAS select tb_Stock.StockID, tb_Goods.GoodsName, tb_Stock.Amount, tb_Stock.Remark from tb_Stock inner join tb_Goods on tb_Stock.GoodsID = tb_Goods.GoodsID;

这段 SQL 的正确思路是:库存表存的是编号和数量,业务人员看不懂编号,通过 inner join 把商品表的名字带出来。视图的价值在于把关联逻辑封装好,应用层只查视图,不用每次写 join——这个习惯到现在依然成立,只是现代项目更习惯用 MyBatis 的关联查询或 JPA 的实体关系映射替代数据库视图。注意报告原文的视图 SQL 只写到 on tb_Stock.G 就断了,明显是复制粘贴丢了一半,上面这段是我按后文语义补全的。这也是实训报告排雷的典型场景:代码要么不全,要么有语法错误,照着抄必翻车。

4. 功能模块实现拆解:登录验证、商品录入与库存联动

4.1 登录模块:身份验证的关键代码与全局登录态管理

报告 6.1 节的登录代码是整个文档里最完整的片段,逻辑很清晰:前端输入用户名和密码,后端拼接 SQL 查询用户表,有记录则登录成功,并把登录名和 ID 存进全局静态变量,后续所有模块通过这个全局变量判断“当前是谁在登录”。核心代码:

public bool Veri(string tb_table, string Id, string Pwd) { DataClass.MyMeans MyClass = new SMMS.DataClass.MyMeans(); bool jud = false; if (Id != "" && Pwd != "") { SqlDataReader temDR = MyClass.getcom( "select * from " + tb_table + " where UserName='" + Id.Trim() + "' and Pass='" + Pwd.Trim() + "'"); jud = temDR.Read(); if (jud) { DataClass.MyMeans.Login_Name = Id.Trim(); DataClass.MyMeans.Login_ID = temDR.GetString(0); DataClass.MyMeans.My_con.Close(); DataClass.MyMeans.My_con.Dispose(); } else { MessageBox.Show("用户名或密码错误!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } MyClass.con_close(); } else MessageBox.Show("请将登录信息添写完整"); return jud; }

逐行说逻辑。getcom 方法返回一个 SqlDataReader,也就是把 SQL 查出来的结果集做流式读取。temDR.Read() 返回 true 说明查到了记录,即用户名密码匹配;然后把 Login_Name 和 Login_ID 写进 MyMeans 的静态字段,这相当于内存里的登录会话,后续所有模块都能读到当前登录人,不用每次操作查一遍库。最后一个参数 tb_table 直接把表名传进来,设计意图是同一个验证方法可以复用给职工登录,但这也意味着表名被拼进 SQL,攻击面更大。

这段代码有两个明显的课程设计风格问题。第一,SQL 是字符串拼接,用户名里传个 ' or '1'='1 就能绕过密码验证,标准的 SQL 注入漏洞;第二,密码在表里存的是明文,登录表 Users_Info 里 passWord 字段直接可读。生产项目至少要预编译或参数化查询,密码要做哈希存储。我一般会这样改造:C# 用 SqlCommand 加 Parameters.AddWithValue,Java 用 PreparedStatement 的 setString,一次到位。

4.2 商品信息管理:录入校验、自动编号与库存表联动

商品管理模块的 btnAdd_Click 是整份报告里信息量最大的代码:先做非空校验,再查重,最后同时向商品表和库存表插入数据。核心代码:

if (txtName.Text == "") { MessageBox.Show("请输入商品名称!"); txtName.Focus(); } else if (txtPrice.Text == "") { MessageBox.Show("请输入商品单价!"); txtPrice.Focus(); } else { txt = txtName.Text.Trim(); SqlDataReader temDR = MyDataClass.getcom( "select * from tb_Goods where GoodsName ='" + txt + "'"); t = temDR.Read(); if (t) { MessageBox.Show("此商品名称已存在!"); txtName.Text = ""; txtName.Focus(); } else { TypeID = My_Set.Tables[0].Rows[comboxType.SelectedIndex][0].ToString(); RecID = MyMC.GetAutocoding("tb_Goods", "GoodsID"); RecID2 = MyMC.GetAutocoding("tb_Stock", "StockID"); Find_SQL = "insert into tb_Goods(GoodsID,GoodsName,TypeID,Remark,Price,Keep) values ('" + RecID + "','" + txtName.Text + "','" + TypeID + "','" + txtRemark.Text + "'," + txtPrice.Text + "," + txtKeep.Text + ")"; Find_SQL2 = "insert into tb_Stock(StockId,GoodsID,Amount) values ('" + RecID2 + "','" + RecID + "',0)"; MyDataClass.getsqlcom(Find_SQL); MyDataClass.getsqlcom(Find_SQL2); MessageBox.Show("添加成功!"); } }

注意这段代码的业务设计,和前面数据库设计对上了:新增商品时,自动调用 GetAutocoding 生成商品编号,同时生成一个库存编号,往 tb_Stock 里插入一条数量为 0 的库存记录。这是很聪明的设计——库存表永远跟着商品表走,新增商品必然产生库存占位记录,避免了“商品存在但库存表查不到”的数据不一致。不少学生实训里只写了商品插入、忘了库存联动,后期做库存查询时永远查不到新商品,就是这个坑。

GetAutocoding 方法没有在报告里给源码,但方法名已经说明了用途:从指定表取出对应字段的当前最大编号,再加一作为新编号。常见做法是查 max(GoodsID) 然后转数字加 1,这个思路在单机课程设计里够用,但并发场景下编号会重复,生产环境应该用数据库自增主键或者序列。参数上,第一个参数是表名,第二个参数是编号字段名,调用方要保证这两个参数和数据库设计一致,否则取出来的编号类型转换会直接异常。

4.3 销售进货与库存模模块:流水记录加库存调整的闭环

报告在第 6 章还覆盖了职工信息管理、供货商信息管理、添加销售信息、添加进货信息、库存信息管理和权限设置管理。从代码风格推断,这些模块套路一致:表单收集数据、校验、拼 SQL、插表、刷新列表。核心业务逻辑不复杂——销售就是往 Sell 表插入一条记录,同时把 Stock 表对应商品的 Amount 减掉;进货则是往 Buy 表插入记录,同时把 Stock 表 Amount 加上。报告对销售和进货的完整代码有所省略,只留了界面图和部分片段,按合格开发的习惯,我应该这样补全销售模块的核心逻辑:

// 伪代码:一份销售单涉及两张表,必须先插流水再扣库存 using (SqlTransaction trans = conn.BeginTransaction()) { SqlCommand cmd = new SqlCommand( "insert into Sell(SellID, GoodsID, Amount, Date) values (@sid, @gid, @amt, @dt)", conn, trans); cmd.Parameters.AddWithValue("@sid", sellId); cmd.Parameters.AddWithValue("@gid", goodsId); cmd.Parameters.AddWithValue("@amt", amount); cmd.Parameters.AddWithValue("@dt", DateTime.Now); cmd.ExecuteNonQuery(); cmd = new SqlCommand( "update Stock set Amount = Amount - @amt where GoodsID = @gid", conn, trans); cmd.Parameters.AddWithValue("@amt", amount); cmd.Parameters.AddWithValue("@gid", goodsId); cmd.ExecuteNonQuery(); trans.Commit(); }

这段补全代码说明了一个关键点:销售操作必须在一个事务里完成“插入销售流水”和“更新库存”两步,要么都成功,要么都回滚。报告原文没有写事务,这是课程设计的常见通病——单表操作没问题,一旦跨表操作就暴露了对数据一致性理解不够。如果你是在这个系统基础上做二次开发,第一件要补的事就是把进销存模块的操作全部包进事务。

权限设置模块相对简单,用的是职工表的 kind 字段(nvarchar 10)区分员工和管理员,管理员能进人事和权限页面,普通员工只能做前台销售。这种权限模型在单机版管理软件里够用,但按现在的标准,权限应该独立成表,做菜单级甚至按钮级控制,而不是一个字段写死。课程设计答辩时,老师问到“怎么控制普通员工不能乱删商品”,回答一个 kind 字段显然是不够的。

5. 实训报告排雷指南:5 个常见的坑与排查思路

5.1 现象:标题 Java,代码全是 C# —— 原因:选题与实现语言脱节

这种问题在实训报告里太常见,甚至是有意为之——先找一份 C# 的超市管理系统照着写,再套上 Java 课程设计的封面。如果你拿到手的报告是这种状态,先别慌,这只是“壳”的问题,骨架是能用的。

解决思路分两支。如果只求交差,按第 6 章的改造清单把代码翻译成 Java 即可;如果想真正学到东西,就借这个机会把两套技术栈对照着看——C# 的 SqlDataReader 对应 Java 的 ResultSet,MessageBox 对应 JOptionPane.showMessageDialog,SqlConnection 对应 Connection,几乎是一一映射。翻译一遍代码,等于同时复习了两个体系,答辩时还能主动指出这一点,反而加分。

5.2 现象:表名前后不一致,SQL 执行报错 —— 原因:文档各章各写各的

报告 5.2 节叫 Goods_Info、Sup_Info,5.3 节建表 SQL 里叫 tb_Goods、tb_Stock,视图 SQL 里又混用 tb_Stock 和 tb_Goods。这不是什么高级错误,就是文档写得不连贯:表设计一章用一套命名,写 SQL 时用了另一套,代码片段里的 SQL 再换一套。我第一次照着做,建完表按 5.2 的字段名写 CRUD,一执行就报“列名无效”。

解决方法是建立“命名唯一”的纪律。写文档时先定一份表名和字段名清单,正文、建表脚本、视图、代码里的 SQL 全部引用同一份清单。我在改造这份报告时,直接用代码片段里那一套命名,也就是 tb_ 前缀,因为登录和商品模块的所有 SQL 都引用 tb_Goods、tb_Stock,数据库设计与代码对齐,改动代价最小。

5.3 现象:登录 SQL 字符串拼接,单引号直接绕过密码 —— 原因:课程设计不设防

前面贴过的登录代码,把 Id 和 Pwd 直接拼进 SQL。我拿测试数据验证过:用户名输入 ' or '1'='1 --,密码随便填,SQL 被拼成 select * from Users_Info where UserName='' or '1'='1' --' and Pass='xxx',后面的密码条件被注释掉,直接以第一行用户身份登录。这在课程设计里几乎人人都有,但不代表可以不改。

正确做法是参数化查询。C# 里用 SqlCommand 加 Parameters.AddWithValue,Java 里用 PreparedStatement 的 setString,SQL 语句先用问号占位,再把值作为参数传入。这样不仅注入失效,SQL 还能预编译复用,性能更好。我见过不少实训项目上线前没修这个洞,被老师用浏览器直接黑掉的案例,别踩。

5.4 现象:商品和库存数据对不上,新商品库存查不到 —— 原因:没有事务保护

商品添加模块里,先 insert tb_Goods 再 insert tb_Stock,两条 SQL 连着执行。如果第二条失败(比如库存表的字段约束冲突),商品已经进了,库存却没了。后面进货时找不到商品,库存查询对不上,排查半天才发现是这里埋的雷。这个问题不像 SQL 注入那么显眼,但它会在系统使用中慢慢暴露,更难定位。

解决:把两条 insert 包进事务。C# 用 SqlTransaction,Java 用 Connection.setAutoCommit(false),两条 SQL 要么都成功,要么都回滚。我在改造时习惯再加一层,把“商品插入”和“库存占位”封装成一个服务方法,上层只调用一次,不在窗体代码里散落 SQL。这样既解决事务问题,也让 UI 层变薄。

5.5 现象:视图 SQL 缺了一半,照抄跑不起来 —— 原因:复制粘贴被截断

报告 5.3 节的库存视图,SQL 写到 on tb_Stock.G 就戛然而止,明显是复制粘贴时丢了后半截。类似的还有第 1 章环境配置写着 Visual Studio 2005,第 3 章又写 Eclipse,互相矛盾。这类问题在答辩前最容易炸——以为是环境问题,其实是文档问题。

这类问题的排查顺序是:先看代码片段能否独立执行,再看表名是否在表设计节有定义,最后核对字段类型和数量。视图 SQL 丢字段就直接补,从表结构一节里抄字段名;环境配置矛盾就以后文的功能模块代码为准——代码是 C#,环境就该是 Visual Studio,前文的 Eclipse 属于复制模板没删干净。这也是实训报告的通病:图可以截图,代码必须手打一遍,否则永远不知道哪里断了。

6. 二次开发改造方案:把 C# 芯的实训报告改造成能跑的 Java 项目

改造的第一步是定技术栈。我建议用 Java Swing 加 JDBC 加 MySQL,理由很直接:报告里的逻辑代码全是过程化的 C# 窗体写法,翻译成 Swing 的 ActionListener 几乎一一对应,不需要引入 Spring 全家桶增加理解负担。如果你后面想往企业级走,再考虑换成 Spring Boot 加 MyBatis,但课程设计阶段用纯 JDBC 反而能把数据库逻辑看得更清楚。

第二步是建表。表结构基本不动,但要按 MySQL 的规则调整类型:char 改 varchar,ntext 改 text,money 改 decimal(10,2),datetime 不变。表名统一用代码片段里的 tb_ 前缀一套,字段名严格对照第 3 章的表设计,不再保留 Goods_Info 那套命名。建表顺序要注意:先建供货商表,再建商品表,再建职工和用户表,最后建进货、销售、库存表,否则外键约束会报错。

第三步就是翻译核心代码。拿登录模块举例,C# 的字符串拼接 SQL 要改成 PreparedStatement 参数化查询,这是改造里最不能省的一步:

String sql = "select loginID from tb_Users where UserName=? and Pass=?"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, userId); ps.setString(2, passWord); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { LoginSession.loginName = userId; LoginSession.loginID = rs.getString(1); return true; } } } return false;

这段代码和 C# 版逻辑等价,但把所有外部输入都当作参数传入,彻底堵住 SQL 注入。LoginSession 对应原报告里的 DataClass.MyMeans,用静态字段保存当前登录人的名称和 ID。商品添加模块同理,把两条 insert 放进同一事务,商品表和库存表要么都成功要么都回滚。验证方式很简单:跑通登录后,连续添加三个商品,再去库存表查记录,应该有三条数量为 0 的占位数据;再做一次销售,库存数量应同步减少。从那以后我每次做课程设计评审,都会先问一句“代码能不能当场跑起来”,并强制把文档、建表脚本、代码 SQL 三者的表名过一遍,确认一致才放行。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表