资讯详情

资讯详情

Oracle 11g + C# 图书管理系统实战模板

简介本资源是一份完整的Oracle数据库课程设计报告文档面向高校计算机、软件工程及相关专业本科生解决数据库系统开发实践中的设计规范、前后端协同与安全性实现等核心问题。报告以图书管理系统为案例覆盖需求分析、E-R建模、Oracle 11g数据库创建含表空间、用户、角色、存储过程与触发器编写、VC/C/C#多语言前台交互实现以及登录验证、权限控制等安全机制设计内容紧扣教学大纲与工程实践要求。资源为单个Word文档.doc格式大小225KB结构清晰含5章完整目录引言、概要设计、数据库分析、详细设计及测试、课程设计心得正文超4000字含数据表结构定义、系统功能模块图、E-R图及关键代码片段。目前已有397人学习下载适合课程设计参考、数据库综合实训复盘与毕业设计前期方案借鉴。1. 这不是一份“交差报告”而是一套可复现、可调试、可迁移的 Oracle 图书管理系统实战模板你手头这份《Oracle数据库课程设计报告.doc》表面看是高校课程作业的 Word 文档但拆开来看——它其实是一套完整闭环的 Oracle 11g C# 桌面应用开发实战组合包从表空间创建、用户权限隔离、外键约束建模到带事务控制的存储过程登录校验、入库逻辑、自动同步库存的触发器再到 C# 端用OracleDataAdapter封装的增删改查链路甚至包含app.config连接字符串配置和ListView数据绑定细节。它不依赖 Oracle APEX 或 Web 容器纯 WinForm Oracle Client 本地直连部署门槛低、调试路径清晰、所有 SQL 和 C# 代码全部贴在文档里没有黑匣子没有隐藏依赖没有“请自行下载驱动”这类玄学提示。适合两类人一是大三学生赶课设 deadline抄完就能跑通二是刚转岗 DBA 或后端的工程师想用最小成本摸清 Oracle 存储过程怎么写、触发器怎么联动、C# 怎么防 SQL 注入——它比官方 Sample 更贴近真实项目节奏有业务逻辑库存上下限预警没写进代码但字段已预留、有安全意识强制用存储过程封装登录、有容错设计try/catch finally close。唯一前提你得有一台能装 Oracle 11g 的 Windows 7/10 机器且愿意花 90 分钟照着文档敲一遍。2. 从零建库表空间、用户、表结构与约束的硬核落地2.1 表空间与用户为什么必须手动建而不是用 SYSTEM课程设计明确要求“数据库安全性设计”而 Oracle 默认用户SYSTEM或SYS拥有 DBA 权限直接用它们开发等于裸奔。文档中create tablespace tushu datafile E:\biaokongjian\tushu.dbf size 32M autoextend on next 32m maxsize 2048m这条命令本质是划出一块独立磁盘区域把图书系统数据物理隔离。关键参数解释autoextend on next 32m当数据文件写满时自动追加 32MB避免因空间不足导致插入失败这是学生调试时最常翻车的点maxsize 2048m上限设为 2GB防止无节制增长吃光磁盘我当年就因漏写这句半夜被监控告警叫醒E:\biaokongjian\tushu.dbf路径必须存在且 Oracle 进程有写权限Windows 下建议用E:\oracle_data\这类非系统盘路径避开 UAC 权限坑。创建用户create user wsn identified by 1234 default tablespace tushu;后必须立刻授权否则连接会报ORA-01045: user WSN lacks CREATE SESSION privilege-- 必须执行的三句授权缺一不可 grant connect, resource to wsn; grant create view to wsn; grant unlimited tablespace to wsn;提示resource角色包含CREATE TABLE、CREATE SEQUENCE等基础权限unlimited tablespace是为了绕过学生常忽略的配额限制quota 0 on tushu会导致建表失败。2.2 表设计外键、空值、字符集的取舍逻辑文档中books表的TID字段定义为varchar2(10)并设外键引用typ(TID)这是典型的关系型建模。但注意三个易错细节外键字段类型必须严格一致typ.TID是varchar2(10)books.TID也必须是varchar2(10)若写成char(10)会导致ORA-02270: no matching unique or primary key for this column-listnot null的业务含义BookName varchar2(40) not null合理书名不能为空但RetailPrice varchar2(10)设为not null有隐患——价格应为number类型varchar2会导致排序错乱如100 99但10 99中文字符支持Oracle 11g 默认字符集AL32UTF8可存中文但若你的数据库是ZHS16GBKvarchar2(10)实际只能存 5 个汉字1 汉字 2 字节此时应改用nvarchar2(10)。建表语句需修正为生产级写法以books表为例create table books ( ISBN varchar2(20) primary key, BookName nvarchar2(40) not null, -- 支持中文且长度准确 TID varchar2(10) not null, RetailPrice number(10,2) not null, -- 价格用 number精度可控 Author nvarchar2(20), Publish nvarchar2(30), StockMin number not null, StockMax number not null, Descriptions nvarchar2(100), constraint fk_books_typ foreign key (TID) references typ(TID) -- 显式命名外键约束 );2.3 视图为什么bookview要选特定字段create view bookview as select isbn,bookname,author,publish,retailprice from books;这个视图看似简单实则暗含权限控制思想屏蔽敏感字段如StockMin、StockMax避免前端误展示库存阈值字段别名全小写isbn而非ISBN规避 C# 中DataTable.Columns[ISBN]大小写敏感问题不含计算字段如StockNum - StockMin保证视图可更新性虽本例未更新但留出扩展空间。注意视图创建后需单独授权给wsn用户grant select on scott.bookview to wsn;文档中误写为scott.yonghu实际应为wsn.bookview因视图属当前用户。3. 存储过程与触发器业务逻辑下沉的核心战场3.1 登录存储过程denglu的缺陷与加固方案原文denglu过程存在三处硬伤密码明文传输upwd number参数将密码当数字传既不安全密码含字母时直接报错又违反最小权限原则SQL 注入风险select t.ename into i from scott.yonghu t where t.enameusername未用绑定变量若usernameadmin or 11可绕过验证状态码语义混乱flag:2表示成功flag:1表示“密码不正确”但flag:0是“用户不存在”前端需额外判断flag1时是否查到用户名。修复后的健壮版本含密码哈希校验create or replace procedure denglu( p_username in varchar2, p_password_hash in varchar2, -- 传入 SHA-256 哈希值非明文 p_result out number, -- 0用户不存在, 1密码错误, 2登录成功 p_user_id out number -- 返回用户ID供后续会话使用 ) as v_count number; v_stored_hash varchar2(64); begin -- 先查用户是否存在 select count(*) into v_count from yonghu where ename p_username; if v_count 0 then p_result : 0; return; end if; -- 查密码哈希并比对 select eno, password_hash into p_user_id, v_stored_hash from yonghu where ename p_username; if v_stored_hash p_password_hash then p_result : 2; else p_result : 1; end if; exception when no_data_found then p_result : 0; when others then p_result : -1; -- 未知错误 end;关键改进① 密码用哈希值比对杜绝明文存储②p_user_id out number返回用户 ID避免前端二次查询③ 错误分支全覆盖p_result语义清晰。3.2 入库存储过程rk的事务边界与并发安全rk过程实现“存在则更新数量不存在则插入新记录”但原文缺少事务控制高并发下可能产生重复插入。修正版加入savepoint和异常回滚create or replace procedure rk( p_isbn in varchar2, p_bname in varchar2, p_rp in number, p_sl in number ) as v_count number; begin -- 设置保存点便于局部回滚 savepoint sp_rk; select count(*) into v_count from inwarehouseitems where isbn p_isbn; if v_count 0 then update inwarehouseitems set shuliang shuliang p_sl where isbn p_isbn; else insert into inwarehouseitems (isbn, bookname, retailprice, shuliang) values (p_isbn, p_bname, p_rp, p_sl); end if; -- 自动触发库存同步见 3.3 节 commit; -- 显式提交避免隐式提交导致触发器失效 exception when dup_val_on_index then rollback to sp_rk; -- 主键冲突时回滚 raise_application_error(-20001, ISBN 重复请检查输入); when others then rollback to sp_rk; raise; end;3.3 库存同步触发器charu的幂等性设计原文触发器charu在INSERT OR UPDATE时更新stock表但存在两个致命问题未处理 DELETE若inwarehouseitems记录被删stock表不会减量导致库存虚高未校验数值合法性shuliang为负数时仍执行操作库存变负。生产级触发器必须满足幂等性同一操作执行多次结果不变create or replace trigger charu after insert or update or delete on inwarehouseitems for each row declare v_stock_count number; begin if inserting or updating then -- 插入或更新时累加数量 select count(*) into v_stock_count from stock where isbn :new.isbn; if v_stock_count 0 then update stock set stocknum stocknum :new.shuliang where isbn :new.isbn; else insert into stock (isbn, stocknum) values (:new.isbn, :new.shuliang); end if; elsif deleting then -- 删除时减去原数量注意此处需用 :old.shuliang update stock set stocknum stocknum - :old.shuliang where isbn :old.isbn; end if; -- 防负库存更新后校验 update stock set stocknum 0 where isbn nvl(:new.isbn, :old.isbn) and stocknum 0; exception when no_data_found then null; -- 无对应库存记录跳过 end;关键点①nvl(:new.isbn, :old.isbn)统一获取 ISBN②update ... set stocknum 0 where stocknum 0强制兜底避免负库存引发业务逻辑崩溃。4. C# 前端连接池、参数化查询与 UI 绑定的避坑指南4.1 连接字符串app.config的隐藏陷阱文档中add keyConStr valueData Sourceorcl;User IDwsn;Password1234;UnicodeTrue/看似标准但Data Sourceorcl依赖tnsnames.ora配置。若未配置应改用 Easy Connect 语法add keyConStr valueData Source(DESCRIPTION(ADDRESS(PROTOCOLTCP)(HOSTlocalhost)(PORT1521))(CONNECT_DATA(SERVICE_NAMEorcl)));User IDwsn;Password1234;UnicodeTrue/提示UnicodeTrue必须开启否则中文显示为??PORT1521是 Oracle 默认监听端口若修改过需同步调整。4.2 数据库连接类database.GetOpen()的线程安全漏洞原文static OracleConnection con是静态单例多线程下必然崩溃OracleConnection 非线程安全。正确做法是每次请求新建连接并利用连接池public static class Database { private static readonly string ConnStr ConfigurationManager.AppSettings[ConStr].ToString(); // 每次调用都新建连接由 Oracle 连接池管理 public static OracleConnection GetOpen() { var conn new OracleConnection(ConnStr); try { conn.Open(); return conn; } catch (Exception ex) { throw new Exception($数据库连接失败: {ex.Message}); } } // 无需手动 Closeusing 语句自动释放 }调用时必须用using保证资源释放public DataTable ss() { var dt new DataTable(); using (var conn Database.GetOpen()) // 自动 Open Dispose using (var cmd new OracleCommand(select * from stock order by ISBN, conn)) using (var adapter new OracleDataAdapter(cmd)) { adapter.Fill(dt); } return dt; }4.3 ListView 绑定se()方法的性能雷区原文se()方法遍历DataRow手动添加ListViewItem在数据量 1000 行时 UI 会卡死。优化方案关闭重绘 批量添加public void se() { listView1.BeginUpdate(); // 暂停重绘 listView1.Items.Clear(); DataTable dt ss(); foreach (DataRow dr in dt.Rows) { var item new ListViewItem(dr[ISBN].ToString()); item.SubItems.Add(dr[StockNum].ToString()); listView1.Items.Add(item); } dt.Clear(); listView1.EndUpdate(); // 恢复重绘一次刷新 }注意listView1.View View.Details;需提前设置否则SubItems不显示列头需手动添加listView1.Columns.Add(ISBN, 100); listView1.Columns.Add(库存, 80);5. 常见问题排查学生调试时踩过的 5 个真实深坑5.1 现象C# 报错ORA-12154: TNS:could not resolve the connect identifier原因Data Sourceorcl在tnsnames.ora中未定义或 Oracle 监听器未启动。解决运行lsnrctl status检查监听器状态若未启动执行lsnrctl start检查ORACLE_HOME\network\admin\tnsnames.ora是否包含ORCL (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST localhost)(PORT 1521)) (CONNECT_DATA (SERVER DEDICATED) (SERVICE_NAME orcl) ) )5.2 现象执行insert into books...报ORA-02291: integrity constraint violated - parent key not found原因插入books表时TID值在typ表中不存在外键约束触发。解决先查typ表select * from typ;若为空插入测试数据insert into typ values(T001, 计算机);关键books.TID必须与typ.TID字符完全一致区分大小写、空格。5.3 现象登录存储过程返回flag1但用户名密码确认正确原因yonghu表中eno是number类型而存储过程中upwd number将密码当数字解析若密码含字母如abc123会报ORA-01722: invalid number异常被捕获后flag保持初始值0但文档逻辑误判为1。解决修改yonghu表alter table yonghu modify eno varchar2(10);重写denglu过程密码参数改为varchar2并用哈希比对见 3.1 节。5.4 现象触发器执行后stock表数据未更新原因触发器未启用或inwarehouseitems表上存在其他触发器冲突。解决检查触发器状态select trigger_name, status from user_triggers where trigger_nameCHARU;若为DISABLED执行alter trigger charu enable;查看触发器编译错误show errors trigger charu;。5.5 现象ListView 显示中文为方框或问号原因.NET Framework版本低于 4.5 且未设置字体或 Oracle 客户端字符集与数据库不匹配。解决在Form_Load中设置字体listView1.Font new Font(Microsoft YaHei, 9F);检查 Oracle 客户端NLS_LANG环境变量set NLS_LANGAMERICAN_AMERICA.AL32UTF8Windows 命令行重启 Visual Studio 使环境变量生效。6. 进阶技巧用一条 SQL 统计全库表数据量替代手工数表6.1 为什么需要这个课程设计报告要求“系统调试”环节验证数据完整性但逐个select count(*) from books; select count(*) from typ;效率极低。Oracle 提供dba_tables视图可批量查询但学生账号默认无权限。解决方案用user_tables当前用户所有表 动态 SQL 生成统计脚本。6.2 一键生成统计 SQL 的存储过程创建gen_table_counts过程输出所有表的行数create or replace procedure gen_table_counts as v_sql clob; begin v_sql : select TABLE_NAME as 表名, NUM_ROWS as 行数 from dual union all ; for t in (select table_name from user_tables order by table_name) loop v_sql : v_sql || select || t.table_name || as 表名, to_char(num_rows) as 行数 from user_tables where table_name || t.table_name || union all ; end loop; -- 去掉末尾的 union all v_sql : rtrim(v_sql, union all ); -- 输出结果实际执行需在 SQL*Plus 中用 执行 dbms_output.put_line(/* 自动生成的统计SQL */); dbms_output.put_line(v_sql); end; /执行后在 SQL*Plus 中运行set serveroutput on exec gen_table_counts; -- 复制输出的 SQL粘贴执行即可得到全表行数6.3 C# 端调用统计结果的实用封装为避免前端拼 SQL封装一个GetTableCounts()方法public Dictionarystring, int GetTableCounts() { var counts new Dictionarystring, int(); using (var conn Database.GetOpen()) using (var cmd new OracleCommand(select table_name, num_rows from user_tables order by table_name, conn)) using (var reader cmd.ExecuteReader()) { while (reader.Read()) { var tableName reader[TABLE_NAME].ToString(); var rowCount Convert.ToInt32(reader[NUM_ROWS]); counts[tableName] rowCount; } } return counts; }调用后可直观展示var stats GetTableCounts(); foreach (var kvp in stats) { Console.WriteLine(${kvp.Key}: {kvp.Value} 行); }6.4 一个血泪教训永远在CREATE TABLE后执行ANALYZE TABLE xxx COMPUTE STATISTICSOracle 11g 的num_rows字段并非实时更新新建表后若不分析user_tables.num_rows为NULL或旧值。必须手动收集统计信息-- 对每张表执行或批量生成脚本 analyze table books compute statistics; analyze table typ compute statistics; analyze table yonghu compute statistics;从那以后我每次建完表都强制走一遍analyze table xxx compute statistics哪怕只是课设——因为count(*)全表扫描太慢而num_rows是唯一能秒出结果的依据。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →