数据库课程设计银行管理系统:从数据字典到C#实现全解析

📅 发布时间:2026/10/11 19:21:31
数据库课程设计银行管理系统:从数据字典到C#实现全解析
简介一份数据库课程设计报告主题为银行管理系统适合数据库课程设计、期末项目及入门开发者参考。报告完整覆盖需求分析、数据库概念结构设计、表结构设计以及C#与SQL Server 2008的实现选型并以管理员和用户两类角色为主线梳理了开户、销户、精确与模糊查询、存款、取款、贷款、转账、还贷、透支信息查看等业务流程包含开户最低存款十元、贷款额度与收入挂钩、转账按卡类型收取0.02或0.05手续费等规则说明。资源为单个doc文档共1个文件压缩包大小2.91MB便于直接阅读和打印已有112人学习下载。具体内容包括用户、银行卡、转账、贷款、还贷、透支等数据表的字段类型与长度设置、E-R关系图、程序流程图以及数据库设计方案可帮助读者理解从业务需求到数据库落地的完整路径也能为撰写同类课程设计报告提供结构参考和细节范例。1. 数据库课程设计里的银行管理系统这份 .doc 能省下你多少重复劳动“数据库课程设计报告——银行管理系统”这份 .doc我拆完之后的判断是它不是一份能直接跑起来的成品源码而是一张“照着敲就能跑”的完整图纸。理由很简单——它把最容易卡住人的三块都写全了需求分析里的业务规则、数据字典里的 28 个字段定义、登录和开户两个模块的 C# 代码。业务上它模拟的是一个小型银行核心管理员开户销户用户存取款、贷款、转账、还贷。适合正在做数据库课程设计想快速交差的学生也适合想用最小成本复现一个带事务约束的银行 demo、准备面试项目的初学者。下面按我复现时会走的顺序从需求到建库、从代码到排错一条线拆完。2. 需求分析与数据字典六张表、两类角色和那些隐藏业务参数拿到课程设计报告我习惯先看需求分析因为后面的表结构和代码全是从这里长出来的。这份报告的需求写得不算花哨但胜在边界清楚管理员和用户两类角色功能划分明确而且每一项功能的约束条件都给了具体数字——开户最低十元、同类卡转账手续费 0.02、异类卡 0.05、透支额度按收入三倍、贷款额度按收入五倍。这些数字看着不起眼却是后面写代码时真正的逻辑开关。2.1 角色与功能矩阵哪些做了、哪些标注了暂未实现先看功能矩阵。管理员和用户的功能在报告里分得很开管理员管的是卡的“生老病死”用户管的是卡上的资金操作。我把它整理成一张表方便后面建表时对照。角色功能执行条件与约束管理员开户最低存入 10 元新用户名同时写用户表 银行卡表老用户名只加银行卡表管理员销户先结清存款、贷款、透支卡上无遗留数据才允许删除管理员精确查询按用户名 / 日期组合条件查询存款与贷款结果回显列表管理员模糊查询需求已定义代码标注未实现用户存款校验卡号 密码后入账用户取款无透支功能的卡不可超余额可透支卡取款后进入透支阶段还清透支才能再取用户贷款额度由用户收入决定代码实现为收入五倍透支状态下也能贷款逾期未还冻结该卡操作用户转账先判断转向卡号存在同类卡手续费 0.02异类卡 0.05金额不能超过当前卡存款用户还贷仅支持一次性还清理论上的分期未实现用户还透支需求已定义代码标注未实现用户查看信息点击按钮查看当前卡的贷款与透支信息注意表里的两个“未实现”模糊查询和还透支。很多课程设计会在需求里写满功能代码却只做一部分这份报告至少把未实现的地方标出来了复现时别在这两个功能上浪费时间。另外用户类型的区分是靠用户表里的“用户类型”字段登录时先验证用户名密码再和下拉框里的类型比对这个流程下面讲登录模块时会展开。2.2 六张表的数据字典字段、类型与主键一眼看全需求分析的第二部分是数据字典报告里给了一张完整的字段表覆盖六张表用户、银行卡、转账、贷款、还贷、透支。摘要里说五张主表实际建库会用到六张——透支表是后补进来的以正文为准。我把 28 个字段浓缩成一张紧凑表。表字段清单类型 / 长度用户用户名 nchar(10) 主键密码 int用户类型 nchar(10)信誉度 int用户收入 int银行卡用户名 nchar(10)卡号 int 主键卡类型 nchar(10)金额 float透支功能 bit透支额度 int贷款额度 int转账转账号 int 主键卡号 int转向卡号 int转账金额 int手续费 float转账利率 float贷款贷款号 int 主键卡号 int贷款金额 int贷款日期 datetime贷款利率 float是否有贷款 bit利息 float应还金额 float还贷卡号 int贷款日期 datetime还款时间 datetime贷款利率 float贷款金额 int利息 float应还金额 float透支透支号 int 主键卡号 int透支金额 int透支开始时间 datetime透支还清时间 datetime这张表一摆出来有三个点立刻值得注意。第一用户表里没有卡号字段因为程序的设计是先验证用户名密码、再进入卡号选择一个用户可以开多张卡卡号归银行卡表管。第二还贷表没有主键这在课程设计的容错范围内但后面做重复还款检查时会踩坑。第三金额类字段的类型明显混用——转账金额、贷款金额是 int手续费、利息却是 float后面第 5 章的精度问题就是在这里埋下的。2.3 业务规则里的参数十元开户、三倍透支、五倍贷款、两级手续费需求分析里散落着一批业务参数它们不是摆设每一条都对应代码里的一个硬编码。复现时最怕的是参数没找全写到一半发现自己造的规则和报告对不上。我按代码逻辑重排了一遍开户最低存入 10 元不足十元直接提示并阻断代码里if (xian 10)就是这道闸。透支额度 用户收入 × 3贷款额度 用户收入 × 5开户时由程序自动计算并写入银行卡表。取款无透支功能的卡余额不足即拒绝有透支功能的卡可以取出不超过透支额度的额外金额但一旦进入透支状态必须还清透支后才能再次取款。转账手续费按卡类型判断转账双方卡类型相同收 0.02不同收 0.05转账金额不能超过当前卡余额。贷款可以在有透支的情况下进行同一个人可以同时背着贷款和透支。还贷一次性还清按贷款日期和还款时间的间隔计算利息应还金额 贷款金额 利息。这些参数在报告里分散在需求分析和开户代码注释中没有单独的配置项。想在复现时调整规则直接改开户代码里的3 * money和5 * money即可。至于贷款利息的具体公式报告只写了“贷款利率由用户选择的贷款时间决定”没给完整算式——常见做法是利息 贷款金额 × 利率 × 期数应还金额再加回本金你可以在存储过程或 C# 代码里按这个口径实现。3. 建库脚本与连接配置把 E-R 模型落成 SQL Server 2008 可执行 SQL需求分析之后就是概念结构设计。报告里的 E-R 图是文字树状拼出来的用户拥有银行卡银行卡关联转账、贷款、还贷、透支。实体关系不复杂基本是一对多一个用户多张卡一张卡多次贷款、多笔转账、多次透支。把它们落成 SQL Server 2008 的建表脚本才算真正拿到可以动手的基础。3.1 六张表建表脚本类型、长度、主键一次对齐报告 1.2.2 的字段表已经给了类型和长度我按 SQL Server 2008 的语法整理成可直接执行的建表脚本。中文表名在中文字段名可以直接用但用方括号包住更稳妥避免和关键字冲突。CREATE TABLE [用户] ( [用户名] nchar(10) PRIMARY KEY, [密码] int NOT NULL, [用户类型] nchar(10) NOT NULL DEFAULT 用户, [信誉度] int NOT NULL DEFAULT 1, [用户收入] int NOT NULL DEFAULT 0 ); CREATE TABLE [银行卡] ( [用户名] nchar(10) NOT NULL, [卡号] int PRIMARY KEY, [卡类型] nchar(10) NOT NULL, [金额] float NOT NULL DEFAULT 0, [透支功能] bit NOT NULL DEFAULT 0, [透支额度] int NOT NULL DEFAULT 0, [贷款额度] int NOT NULL DEFAULT 0 ); CREATE TABLE [转账] ( [转账号] int PRIMARY KEY, [卡号] int NOT NULL, [转向卡号] int NOT NULL, [转账金额] int NOT NULL, [手续费] float NOT NULL DEFAULT 0, [转账利率] float NOT NULL DEFAULT 0 ); CREATE TABLE [贷款] ( [贷款号] int PRIMARY KEY, [卡号] int NOT NULL, [贷款金额] int NOT NULL, [贷款日期] datetime NOT NULL, [贷款利率] float NOT NULL, [是否有贷款] bit NOT NULL DEFAULT 1, [利息] float NOT NULL, [应还金额] float NOT NULL ); CREATE TABLE [还贷] ( [卡号] int NOT NULL, [贷款日期] datetime NOT NULL, [还款时间] datetime NOT NULL, [贷款利率] float NOT NULL, [贷款金额] int NOT NULL, [利息] float NOT NULL, [应还金额] float NOT NULL ); CREATE TABLE [透支] ( [透支号] int PRIMARY KEY, [卡号] int NOT NULL, [透支金额] int NOT NULL, [透支开始时间] datetime NOT NULL, [透支还清时间] datetime NULL );参数说明nchar(10)是定长 Unicode 字符用户名和卡类型用它足够bit对应 C# 的 bool透支功能和是否有贷款都是开关型字段datetime存日期时间贷款日期、还款时间、透支起止时间都用它金额字段先按报告原文建跑通之后再按第 5 章说的改成decimal(18,2)。原报告里还贷表没有主键我暂时也保留业务逻辑上的隐患后面单独讲。建表顺序有个讲究先建用户表再建银行卡表因为银行卡的用户名要引用用户表。转账、贷款、还贷、透支都挂在银行卡的卡号上严格说应该最后建但这里四张表互不依赖顺序不影响。3.2 关系与完整性补上外键约束不让程序唱独角戏报告原文建表时没有建任何外键这是课程设计里很常见的简化靠 C# 代码先查后插来保证数据一致性。但 E-R 图里明明画出了“用户拥有银行卡”“银行卡产生贷款”这种关系不落成外键约束的话数据库层面就少了一道防线。我复现时会把外键补上ALTER TABLE [银行卡] ADD CONSTRAINT FK_Bank_User FOREIGN KEY ([用户名]) REFERENCES [用户]([用户名]); ALTER TABLE [转账] ADD CONSTRAINT FK_Transfer_Card FOREIGN KEY ([卡号]) REFERENCES [银行卡]([卡号]); ALTER TABLE [贷款] ADD CONSTRAINT FK_Loan_Card FOREIGN KEY ([卡号]) REFERENCES [银行卡]([卡号]); ALTER TABLE [还贷] ADD CONSTRAINT FK_Repay_Card FOREIGN KEY ([卡号]) REFERENCES [银行卡]([卡号]); ALTER TABLE [透支] ADD CONSTRAINT FK_Over_Card FOREIGN KEY ([卡号]) REFERENCES [银行卡]([卡号]);补完外键的一个重要变化落在销户逻辑上需求要求卡上无贷款、无透支、无遗留数据才能销户原文的程序代码只删了银行卡表如果卡号在贷款表或透支表里有残留记录加了外键后删除会被数据库直接拒绝等于程序漏掉的检查由数据库兜底。这也是我在课程设计里一贯的做法——程序是业务规则的第一道防线外键和约束是第二道两者都装上才敢叫“完整”。3.3 连接串与老 API 兼容ConfigurationSettings 过时后的正确写法报告代码里读连接串用的是一行老代码System.Configuration.ConfigurationSettings.AppSettings[DB]。这是 .NET 2.0 时代的写法在现在的 Visual Studio 里编译会提示已过时但还能跑前提是项目引用了 System.Configuration.dll并且在 App.config 的 appSettings 里加了 DB 这个键。?xml version1.0 encodingutf-8 ? configuration connectionStrings add nameBankDB connectionStringServer.;DatabaseBankDB;Integrated Securitytrue providerNameSystem.Data.SqlClient / /connectionStrings /configuration如果跟着原文走App.config 里应该写add keyDB valueServer.;DatabaseBankDB;Integrated Securitytrue/代码里保持 ConfigurationSettings 不动。但我的习惯是顺手升级成ConfigurationManager.ConnectionStrings[BankDB].ConnectionString原因有二一是新版框架里 ConfigurationSettings 长期处于过时状态说不定哪天就不认了二是 ConnectionStrings 节点语义更清晰和 SqlClient 的对应关系一目了然。注意连接串里的Integrated Securitytrue是 Windows 身份验证适合本机调试如果用 SQL Server 身份验证要改成User IDsa;Password你的密码。课程设计在实验室机器上跑前者通常最省事。4. 登录与开户模块下拉菜单填充、身份校验和额度计算的 C# 实现报告的程序实现部分给了登录界面和管理员界面的关键代码严格说不是完整源码但核心逻辑都在。这两个模块恰好也是整个系统里最值得看的代码——登录的校验顺序、开户的额度计算都是能直接抄走改到自己项目里的东西。4.1 登录下拉菜单select distinct 用户类型不硬编码角色登录界面有个细节做得很讲究用户类型下拉框不是写死“管理员”和“用户”而是启动时从用户表里查出来的。这样设计的好处是如果数据库里没有管理员类型记录界面上下拉框里就没有“管理员”这一项安全性比硬编码高了一截。原文代码我整理成了更规范的写法private void loginform_Load(object sender, EventArgs e) { string constr ConfigurationManager.ConnectionStrings[BankDB].ConnectionString; using (SqlConnection con new SqlConnection(constr)) { SqlCommand com new SqlCommand(select distinct 用户类型 from 用户, con); con.Open(); SqlDataReader result com.ExecuteReader(); string[] types new string[3]; // 当前系统只有管理员和用户两类 int i 0; while (result.Read()) { types.SetValue(result[用户类型].ToString(), i); i; } loginlist.DataSource types; // 下拉框数据源绑定 } }逻辑说明先读连接串再用select distinct 用户类型 from 用户把不重复的角色列表查出来存入数组后直接绑定为下拉框数据源。原文把连接对象 con 和命令对象 com 定义为窗体成员变量我这里改用 using 块局部变量避免连接对象在窗口存活期间一直占着不放。参数说明数组容量原代码写死为 3理由是用户类型只有管理员和用户两种。这个容量其实有隐患如果以后在用户表里加一个“柜员”角色数组就会越界。复现时建议改成Liststring动态扩容一行代码的事。另一个值得注意的点是distinct关键字如果数据库里混入了重复的用户类型记录它会自动去重不会在下拉框里出现两行一模一样的“用户”。4.2 登录校验先密码后类型拼接 SQL 要改成参数化原文的登录校验流程是两步走先按用户名查密码比对成功后查用户类型再和下拉框选中值比对最后按类型跳转到管理员界面或用户界面。第二步校验里有个隐患——用户不存在时直接对空结果取值会抛异常。我把两步合并成一次查询顺便把字符串拼接的 SQL 改成了参数化查询private void loginbutton_Click(object sender, EventArgs e) { string constr ConfigurationManager.ConnectionStrings[BankDB].ConnectionString; string name this.usernametxt.Text; string code this.usercodetxt.Text; using (SqlConnection con new SqlConnection(constr)) { con.Open(); SqlCommand com new SqlCommand( select 密码, 用户类型 from 用户 where 用户名 name, con); com.Parameters.AddWithValue(name, name); SqlDataReader result com.ExecuteReader(); if (!result.Read()) { MessageBox.Show(用户名不存在或密码错误请重新输入); return; } if (result[密码].ToString() ! code) { MessageBox.Show(用户名不存在或密码错误请重新输入); return; } string dbType result[用户类型].ToString(); if (loginlist.Text.Trim() dbType) { if (dbType 管理员) { this.Hide(); 管理员.admin ad new 管理员.admin(this); ad.Show(); } else { this.Hide(); 用户.cardselect1 se new 用户.cardselect1(this, name); se.Show(); } } else { MessageBox.Show(用户名不存在或密码错误请重新输入); } } }逻辑说明一次查询取出密码和用户类型两个字段先调result.Read()判断记录是否存在再逐项比对。比对通过后按用户类型分发到不同窗体name作为参数传给下一个界面个户在选择卡号时能直接知道自己是谁。参数说明name是 SqlParameter 参数占位符对应原文拼接的name。原文写法在用户名含单引号时会直接报 SQL 语法错误参数化不存在这个问题。这是从课程设计代码迈向工程化代码的第一步建议保留这个改动。另外result[密码].ToString()和用户输入做的是字符串比较原文里密码字段是 int 类型这里在复现时会遇到一个奇怪的问题——见第 5 章。4.3 开户新老用户分叉、最低十元、额度公式与原文漏字段开户模块是管理员界面的核心功能逻辑分三条线最低存入十元的校验、新老用户的分叉处理、透支额度和贷款额度的自动计算。原文代码里有个 bug老用户且不开通透支功能时insert 语句漏写了“透支额度”列照抄会直接报“列名或所提供值的数目与表定义不匹配”。我整理时补全了Random ro new Random(); int cardNo ro.Next(100, 999); // 随机卡号冲突问题见第5章 int deposit int.Parse(this.textBox4.Text); // 开户存款金额 int income int.Parse(this.textBox5.Text); // 月收入 int overLimit 3 * income; // 透支额度 收入 × 3 int loanLimit 5 * income; // 贷款额度 收入 × 5 if (deposit 10) { MessageBox.Show(开户至少存入十元); return; } if (isNewUser) { if (this.textBox2.Text ! this.textBox3.Text) { MessageBox.Show(请重新确认密码!); return; } // 新用户用户表和银行卡表都要插入 string sqlUser insert into 用户(用户名,密码,用户类型,信誉度,用户收入) values(name,code,用户,1,income); string sqlCard insert into 银行卡(用户名,卡号,卡类型,金额,透支功能,透支额度,贷款额度) values(name,card,bank,deposit,overFunc,overLimit,loanLimit); // 依次执行两条 insert } else { // 老用户只插银行卡表 string sqlCard insert into 银行卡(用户名,卡号,卡类型,金额,透支功能,透支额度,贷款额度) values(name,card,bank,deposit,overFunc,overLimit,loanLimit); }逻辑说明开户先取四个输入值——卡类型、存款金额、月收入、是否开通透支功能然后算出透支额度和贷款额度。存款低于十元直接阻断。新用户要求确认密码一致并同时写用户表和银行卡表老用户只加一张卡。isNewUser是前面“点击查询”按钮查出来的结果查得到就是老用户查不到就是新用户同时会把密码框和收入框设为只读防止冒充已有用户开户。参数说明3 * income和5 * income就是 2.3 节说的额度和收入挂钩规则。原报告里这两行代码直接写在开户方法里属于硬编码想调比例只需要改这两个乘数。cardNo用的是Random.Next(100, 999)这是一个会在开户量稍大时爆雷的设计——每次随机生成的卡号可能重复而卡号又是银行卡表主键具体现象和解决见第 5 章。提示原文代码大量使用字符串拼接 SQL开户、登录、查询都这样。我整理出来的版本全部换成了name这类参数占位符。如果你照着原文敲数据库里一旦出现含单引号的用户名或者用户输入的密码里带特殊字符程序就会在 ExecuteNonQuery 这一步抛异常。5. 常见问题排查卡号冲突、float 精度和销户残留的五个坑这一章是血泪经验的集中区。下面五条坑不是瞎猜全部能从报告原文的代码和表结构里直接找出来。每一条我都按“现象 → 原因 → 解决”写方便你对照自己的报错信息快速定位。5.1 随机卡号撞主键100-999 只有 900 个组合现象连续开户多次后偶尔在 insert 银行卡时弹出“违反 PRIMARY KEY 约束”或者两张卡的卡号相同后存入的卡覆盖了前面的显示结果。原因开户代码用Random ro new Random(); int cardNo ro.Next(100, 999);生成卡号。三位数的随机数只有 900 种组合而且new Random()在极短时间连续调用时可能拿到相同种子产生相同的随机数序列。卡号又是银行卡表主键重号必炸。解决加一层查重循环插入前先查卡号是否已存在存在就重新生成重试三次仍冲突就报错。更根本的做法是把卡号改成数据库自增列比如bigint IDENTITY(10000001,1)从 10000001 开始递增既保证唯一又不依赖程序侧随机数第 6 章会给出具体改法。5.2 金额用 float存取几次后出现 99.999999现象用户存了 100 元又取走 50 元余额显示不是 50.00而是 49.999999 或 50.000001 这种带一长串小数位的值。原因银行卡表的金额字段用的是 float它是二进制浮点类型本身无法精确表示大多数十进制小数。存取款涉及加减运算误差会累积银行场景对账时这种“分钱不对”的问题就是从这里来的。解决把金额字段全部改成decimal(18,2)这是 SQL Server 里最常用的货币精度类型18 位总长度、2 位小数。同时把转账金额、贷款金额、透支金额这几个字段一并从 int 升级到 decimal——int 存金额还有另一个问题金额小于 1 元时直接截断成 0。5.3 销户与需求不符代码没检查贷款和透支就删卡现象卡上明明还有未还贷款销户却能成功贷款记录变成孤儿数据永远挂在一个已被删除的卡号下面。原因需求分析里写了“销户前必须结清存款、贷款、透支”但销户代码只对银行卡表执行了 delete没有先查询贷款表、透支表、转账表里是否有该卡号的记录。程序漏了检查数据库又没有外键约束删除自然畅通无阻。解决两条路都走。程序侧在 delete 前加三条查询贷款表、透支表、转账表各统计一次有记录就不允许销户数据库侧把第 3 章的外键约束补上即使程序漏查数据库也会以主外键冲突的方式拒绝删除。外键是最后的后悔药程序检查是第一道防线。5.4 密码字段用 int 拼接 SQL引号用户名直接报错现象用户名输入 ONeal 这类带单引号的字符串登录直接抛 SQL 语法异常或者用户设置的密码是 000123存进数据库后变成 123下次登录怎么输都进不去。原因密码字段在数据字典里定义为 int 类型。int 会把前导零吃掉000123 写入后变成 123登录时用户输入的“000123”转成字符串比对根本对不上。单引号报错则是因为登录 SQL 用了字符串拼接引号没有做转义处理。解决密码字段从 int 改成nvarchar(50)存储原样字符串。SQL 全部改成参数化查询让 SqlParameter 处理特殊字符。更进一步的做法是给密码做哈希存储不在数据库里保存明文——课程设计可以不做但参数化和改类型这两步建议保留。5.5 还贷表无主键重复还款产生脏数据现象用户重复点击还贷按钮还贷表里出现多条完全相同的记录对账时还款总额是实际应还金额的两倍。原因还贷表没有主键也没有任何唯一约束同一笔贷款可以无限次插入还贷记录。程序侧没有在还贷前检查贷款表的状态重复点击就重复 insert。解决给还贷表加一个自增主键还贷流水号 bigint IDENTITY(1,1)让每条记录有唯一标识。程序侧在还贷前先查贷款表的“是否有贷款”字段状态已是 0 就直接提示“该笔贷款已还清”。这样即使按钮被快速点击两次第二次也会被状态检查拦下来。6. 验证技巧用一组 SQL 给银行管理系统做体检复现完成后怎么确认系统是真能跑、而不是刚好没触发雷我的习惯是不依赖界面点点点直接在 SSMS 里跑一组校验 SQL。这套查询能从数据层把表结构里的隐患暴露出来比人工点按钮快得多。6.1 四条查询把脏数据揪出来-- 1. 用户与卡数量正常情况每个用户至少一张卡 SELECT u.用户名, COUNT(b.卡号) AS 卡数 FROM 用户 u LEFT JOIN 银行卡 b ON u.用户名 b.用户名 GROUP BY u.用户名; -- 2. 透支额度校验开户逻辑应为 用户收入 × 3 SELECT b.用户名, b.卡号, b.透支额度, u.用户收入 FROM 银行卡 b JOIN 用户 u ON b.用户名 u.用户名 WHERE b.透支额度 3 * u.用户收入; -- 3. 应还金额校验应还金额 贷款金额 利息 SELECT 贷款号, 卡号, 贷款金额, 利息, 应还金额 FROM 贷款 WHERE ABS(应还金额 - (贷款金额 利息)) 0.01; -- 4. 还贷表重复检查 SELECT 卡号, 贷款日期, COUNT(*) AS 次数 FROM 还贷 GROUP BY 卡号, 贷款日期 HAVING COUNT(*) 1;每条查询的用途很直接。第一条查用户和银行卡的 1:N 关系是否成立有没有用户一张卡都没有的异常第二条验证开户时透支额度是否真的等于收入三倍如果查到记录说明代码里的额度公式被改过或 insert 写错第三条检查贷款利息计算是否一致ABS比较允许 0.01 以内的浮点误差超过就说明金额精度出问题了第四条专门盯还贷表的重复记录有结果就按第 5 章第 5 条处理。6.2 顺手把卡号生成改成 IDENTITY一劳永逸如果体检跑出了卡号冲突的问题最省事的改法是动表结构而不是动代码。卡号从程序生成的随机 int 改成数据库自增列开户时不再关心“生成什么卡号”插入后把自增值取回来展示即可CREATE TABLE [银行卡] ( [卡号] bigint IDENTITY(10000001,1) PRIMARY KEY, [用户名] nchar(10) NOT NULL, [卡类型] nchar(10) NOT NULL, [金额] decimal(18,2) NOT NULL DEFAULT 0, [透支功能] bit NOT NULL DEFAULT 0, [透支额度] int NOT NULL DEFAULT 0, [贷款额度] int NOT NULL DEFAULT 0 );这里一并把金额字段改成了 decimal(18,2)顺手解决第 5 章的精度坑。C# 侧插入完成后用SELECT SCOPE_IDENTITY()拿到新卡号再弹窗告诉用户。从那以后我拿到任何一份数据库课程设计文档第一件事都是先把六张表建出来跑一遍上面第二条和第三条查询确认表结构和业务对得上再去看 C# 代码——表结构不先钉死代码里写再多判断都是纸面保障。希望帮到你。本文还有配套的精品资源点击获取