多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Oracle 11g实例源程序实战:从环境搭建到PL/SQL调试

Oracle 11g实例源程序实战:从环境搭建到PL/SQL调试 简介一套面向Oracle 11g初学者的实例源码包源自《Oracle 11g从入门到精通第二版》覆盖19章核心知识点适合数据库入门者与需要动手实践的在职工程师。压缩包共495个文件大小仅1.21MB包含236个txt脚本与说明、44个java程序、123个class编译文件、36个xml配置及17个bak备份文件等可对照书籍章节逐步运行与调试。目前已有404人学习下载。包里按章节组织从环境安装、SQL与表索引到视图、存储过程、触发器再到权限管理、备份恢复与性能优化均有对应实例备份恢复相关脚本如recover_database、backup_tablespace等可直接用于模拟故障场景帮助读者理解Oracle的运行机制。通过动手运行这些程序能直观体会SQL调优、数据备份等场景的实际效果既适合自学也适合教学参考。1. 这包实例源程序到底值不值得折腾Oracle 11g 从入门到精通的另一半很多人都在找 oracle11g从入门到精通 这类书的配套代码因为看数据库书最容易犯的错就是只看不敲。光盯着 SQL*Plus 里的查询结果看最多记住语法记不住表结构和游标的执行顺序。这套第二版的实例源程序把书中每章用到的建表脚本、PL/SQL 块、存储过程、触发器集中在一个压缩包里省去逐字敲示例代码的时间也把“照着书敲、敲完还报错”的挫败感挡在门外。它解决的是动手层面的三个实际问题环境怎么搭、完整示例去哪找、跑不起来怎么查。适合刚转 Oracle 开发的程序员、复习备考的数据库方向学生以及想把旧项目 SQL Server 写法改造成 Oracle 写法的开发。这里说的“实例源程序”是配套示例源码包不是数据库实例本身分清这点后面读代码思路会顺很多。2. 先跑通再谈精通Oracle 11g 环境搭建与实例库导入的关键三步拿到源码包后先别着急解压环境选型不对后面所有实验都会在安装和字符集上消耗大量时间。这一章按我自己踩过的顺序来版本选择、解压导入、验证实例。2.1 版本选择先看边界32位与64位、Windows与Linux的实际取舍Oracle 11g 的版本线里11.2.0.4 是官方稳定分支的终点网上能搜到的补丁、案例基本都围绕它展开。如果你机器上已经装了 11.2.0.1 或更早的小版本建议优先补到 .4后文调试要用的 DBMS_XPLAN 和绑定变量查询在旧版本里表现会差一截。选型上有一条硬边界Windows 开发机内存超过 8GB 时32 位版本会受限于约 2GB 的用户地址空间跑书里排序、物化视图相关实验容易直接报 ORA-04030 内存耗尽。场景推荐配置说明Windows 开发机Oracle 11g R2 11.2.0.4 x64兼容性最稳SQL*Plus 与图形工具都能稳定挂接Linux 测试机11.2.0.4 Linux x64字符集建议 AL32UTF8配合客户端 NLS_LANG 才不乱码老机器 4GB 内存以下11g 32 位只跑前几章基础 SQL 够用后半部分性能实验会吃力选型定下来后还有一件事值得提前做准备好一个干净的目录专门放脚本。不要解压到中文路径不要放桌面也不要放网盘同步目录。这套源码里几十个 .sql 文件SQL*Plus 在 Windows 下对中文目录的支持一言难尽报 SP2-0310 时你分不清是路径问题还是编码问题。我一般建C:\ora_work或~/ora_work所有实验文件都从这里进出路径越短越省心。2.2 解压、登入、执行把实例源程序导进数据库的完整动作解压完成后第一步是确认登录账号。书中示例账号几乎都是scott但 11g 默认安装时这个账号是锁定的直接拿文档里的scott/tiger去连通常会收到账号锁定的报错。常见做法是先用系统管理员身份解锁并授权sqlplus / as sysdba ALTER USER scott IDENTIFIED BY tiger ACCOUNT UNLOCK; GRANT CONNECT, RESOURCE TO scott;逻辑说明这三行解决的是“文档写着账号密码却连不上”的问题。11g 出于安全收紧示例账号默认锁定必须先解锁。GRANT CONNECT, RESOURCE给的是建表、建序列、建过程的基础权限跑完整本书的建表和 PL/SQL 脚本够用。如果后面要跑 AWR 相关的实验只需再追加GRANT SELECT ON v_$session TO scott这类细粒度授权不建议直接给 DBA 角色否则后面观察权限对查询计划的影响时现象会被管理员权限掩盖。登录账号就绪后执行源码的通用姿势是sqlplus scott/tigerorcl C:\ora_work\chapter_02\create_table.sql C:\ora_work\chapter_02\insert_data.sql逻辑说明是 SQLPlus 里执行脚本文件的命令和直接在提示符下敲 SQL 的区别在于脚本文件内可以包含注释、SET 参数、PL/SQL 块语句按文件内部行序依次执行。这里先跑建表后跑插入是有依赖的插入脚本引用的表结构必须已经存在。路径用绝对路径是避免对 SQLPlus 当前工作目录的误判。Windows 上双击图标启动的 SQL*Plus工作目录经常不是你解压源码的目录用绝对路径最保险。参数说明orcl是默认服务名安装时改过实例名就要用实际名字后面也可以带相对路径前提是你先执行过HOST cd /d C:\ora_work这类目录切换否则老老实实用绝对路径。另外注意脚本里如果带 SPOOL 命令它会尝试写日志文件需要确保当前系统用户对目标目录有写权限否则会报 SP2-0667 卡在导出环节。2.3 用一条查询验证实例表、表空间与用户的三个检查点导入完不能急着往后翻书先做三个验证。第一个验证能确认当前账号下的表有没有建进来第二个确认数据文件实际落盘位置第三个确认账号状态避免后面章节再次连不上时怀疑人生SELECT table_name FROM user_tables WHERE ROWNUM 10; SELECT tablespace_name, file_name FROM dba_data_files; SELECT username, default_tablespace, account_status FROM dba_users WHERE username IN (SCOTT, SYSTEM);逻辑说明第一句查询当前账号下前 10 张表user_tables只返回登录账号拥有的表排除其他模式的影响。第二句查数据文件路径后面建表空间时能避开路径冲突。第三句确认账号状态是 OPEN 而不是 EXPIRED。参数说明dba_data_files需要较高的系统权限scott默认没这个权限遇到权限不足时换成ALL_TABLES或直接跳过只看前两条也够用。ROWNUM 10是 Oracle 特有的伪列截断方式MySQL 习惯的LIMIT在这里不生效这是常见的语法混淆点。还有一个习惯值得养成不要整包脚本一次性进去。几百行脚本跑到中间报错你只能从头翻错误位置非常被动。按章节把脚本拆开执行哪一章挂了你只排查哪一章定位成本会直线下降。3. 实例源码里藏着的主线从建表到触发器的五类典型模块这套源码最大的价值不是能跑通而是它展示了 Oracle 与 MySQL、SQL Server 写法上的关键差异。我在复现过程中把这部分内容拆成五类模块对应实际开发里最高频的五个场景。3.1 建表脚本看约束、主外键与索引的书写习惯源码里第一个值得抄的对象是建表语句。表本身不算复杂但体现 Oracle 写法的一个明显特征显式约束命名。几乎所有主键、外键、检查约束都有明确名字而不是依赖数据库自动生成。下面这段是从配套资源展示的典型范式里提炼出的写法CREATE TABLE dept ( deptno NUMBER(2) CONSTRAINT pk_dept PRIMARY KEY, dname VARCHAR2(14) CONSTRAINT nn_dname NOT NULL, loc VARCHAR2(13) ); CREATE TABLE emp ( empno NUMBER(4) CONSTRAINT pk_emp PRIMARY KEY, ename VARCHAR2(10) CONSTRAINT nn_ename NOT NULL, deptno NUMBER(2), CONSTRAINT fk_emp_dept FOREIGN KEY (deptno) REFERENCES dept(deptno) );逻辑说明这是经典的部门-员工主外键结构。外键约束写在表级而不是列级好处是能表达多列组合外键也方便后期统一管理。CONSTRAINT后面的名字是约束标识将来要删约束直接DROP CONSTRAINT pk_dept不需要去数据字典里查系统生成的随机名。参数说明VARCHAR2(14)里的 14 是字节数上限Oracle 默认按字节计算存储中文要注意实际占用的字节数。NUMBER(2)表示整数部分最多两位想存小数就写NUMBER(6,2)这种精度加小数位的组合。这里要特别提醒Oracle 没有 MySQL 那种AUTO_INCREMENT自增要靠序列加触发器实现这点在 3.4 节会展开。3.2 PL/SQL 块游标、异常与隐式循环的示范代码PL/SQL 部分最值得学的是游标使用习惯。书上处理多行数据时几乎都用显式游标加 FOR 循环让 Oracle 隐式完成打开、抓取、关闭的动作这比手动OPEN、FETCH、CLOSE少写几行也少犯忘记关闭游标的错DECLARE CURSOR cur_emp IS SELECT ename, sal FROM emp WHERE deptno 10; BEGIN FOR rec IN cur_emp LOOP DBMS_OUTPUT.PUT_LINE(员工: || rec.ename || , 薪资: || rec.sal); END LOOP; END; /逻辑说明FOR rec IN cur_emp里的rec是游标行的隐式记录类型不需要自己定义变量去接收每一列。循环结束后 Oracle 会自动关闭游标这是比手动OPEN/CLOSE更不容易出错的写法。参数说明cur_emp是游标名位置可以换rec.ename是 PL/SQL 记录类型的字段引用字段名必须和 SELECT 列表里的列名或别名一致。结尾的/是 SQL*Plus 中执行 PL/SQL 块的提交符漏掉它会让你卡在读下一个语句上。配套源码里大量使用WHEN NO_DATA_FOUND THEN做异常处理但WHEN OTHERS THEN后面一定要跟着SQLERRM或DBMS_OUTPUT.PUT_LINE否则异常会被吞掉排查时凭空多花几倍时间。3.3 存储过程与函数IN、OUT、IN OUT 三种参数模式怎么用配套源码把三种参数模式放在同一个过程里对比这是很实用的讲解方式。IN负责输入OUT负责带回结果IN OUT则是可读可改的复用参数CREATE OR REPLACE PROCEDURE get_emp_info ( p_deptno IN NUMBER, p_count OUT NUMBER, p_sql IN OUT VARCHAR2 ) AS BEGIN SELECT COUNT(*) INTO p_count FROM emp WHERE deptno p_deptno; p_sql : SELECT * FROM emp WHERE deptno || p_deptno; DBMS_OUTPUT.PUT_LINE(生成查询语句: || p_sql); END; /逻辑说明这个例子同时展示了三种模式的职责分配。p_deptno只能读取p_count在过程内被赋值调用方在过程结束后才能拿到有效值p_sql既接收调用方传入的旧字符串又在过程内部拼出新字符串。参数说明OUT参数如果中途异常退出调用方拿到的是NULL所以调用代码要记得做空值判断。IN OUT参数不能从调用端直接传字面量比如get_emp_info(10, v_cnt, x)会报 PLS-00236必须声明一个变量传进去。在 SQL*Plus 里调用的标准套路是先用VARIABLE v_cnt NUMBER声明绑定变量再EXECUTE get_emp_info(10, :v_cnt, :v_sql)。3.4 触发器与序列业务联动逻辑的正确打开方式Oracle 没有自增列配套方案是序列加触发器这是模仿 MySQL 自增主键的标准替代品CREATE SEQUENCE seq_emp_id START WITH 100 INCREMENT BY 1; CREATE OR REPLACE TRIGGER trg_emp_before_insert BEFORE INSERT ON emp FOR EACH ROW BEGIN IF :NEW.empno IS NULL THEN SELECT seq_emp_id.NEXTVAL INTO :NEW.empno FROM DUAL; END IF; END; /逻辑说明BEFORE INSERT定义触发器在插入动作真正落盘之前运行FOR EACH ROW表示它是行级触发器每插入一行就触发一次。:NEW是行级触发器中的新行占位符把序列取到的下一个值写进empno字段。参数说明START WITH 100决定序列起点改成 1 就从 1 开始。INCREMENT BY 1是步长。加IF :NEW.empno IS NULL这个判断是为了允许手动指定主键值手动传值时不覆盖。这里有个容易误判的点序列不参与事务回滚哪怕插入语句最终回滚了序列值也已经消耗掉主键会出现空洞这是 Oracle 的设计行为不是故障。3.5 视图与同义词权限收口前的最后一道封装源码后半部分引入视图机制目的是让报表查询不直接触碰底层表。配套写法通常是简单视图加同义词把对象名缩短同时隐藏真实表名CREATE OR REPLACE VIEW v_emp_dept AS SELECT e.empno, e.ename, d.dname FROM emp e JOIN dept d ON e.deptno d.deptno; CREATE SYNONYM emp_v FOR v_emp_dept;逻辑说明视图把两表关联封装成一个逻辑对象调用方只面对v_emp_dept这一个名字。同义词让调用方可以不带模式名前缀访问对象实际效果类似给对象起个别名。如果底层表结构要调整只需要改视图定义所有依赖视图的查询语句不用动。参数说明CREATE OR REPLACE VIEW里的OR REPLACE允许同名视图被覆盖更新省去先 DROP 再 CREATE 的两步操作。同义词本身不传递权限授予用户访问emp_v之前必须给该用户授予v_emp_dept的 SELECT 权限否则同义词会变成空壳。4. 跟着源码跑实验最容易翻的四个坑与排查套路复现这套源码时环境问题占了大约一半的排错时间。这个章节我按“现象 → 原因 → 解决”的顺序整理几条踩过的坑。4.1 现象ORA-01033 数据库实例起不来卡在“初始化或关闭中”现象按书里的步骤启动数据库SQL*Plus 提示ORA-01033: Oracle initialization or shutdown in progress等多久都进不去。原因最常见的触发点是上一次数据库被强制关闭重做日志和联机数据文件没有一致化。另一个可能原因是安装后改过数据文件路径但控制文件里的指针还指向旧位置。解决用系统管理员身份做一次一致恢复sqlplus / as sysdba STARTUP MOUNT; ALTER DATABASE RECOVER; ALTER DATABASE OPEN;逻辑说明STARTUP MOUNT只加载控制文件不打开数据文件RECOVER应用重做日志里的变更让数据文件和控制文件对齐OPEN正常放行读写。如果RECOVER阶段提示缺少归档日志先查V$RECOVERY_LOG再决定是补日志还是放弃该次恢复。参数说明执行这套命令要求当前系统用户具备 SYSDBA 权限。ALTER DATABASE OPEN不要顺手加RESETLOGS除非你确认日志真的丢了否则会导致日志序列重置后续备份策略会受到影响。4.2 现象ORA-00942 表或视图不存在刚跑的建表脚本白跑了现象上午刚跑完建表脚本下午执行 SELECT 却报ORA-00942: table or view does not exist。原因先排查你是不是换了一个会话连错了账号。检查 SQL*Plus 顶部横幅用户是SCOTT还是SYSTEM。第二个常见原因是建表和查询分属不同模式名比如BOOK用户建的表scott自然查不到。第三个原因是同义词缺失视图、同义词这类封装对象一旦被 DROP查询里引用的名字就成了空壳。解决三步走SELECT owner, table_name FROM all_tables WHERE table_name EMP; SHOW USER; SELECT * FROM scott.emp WHERE ROWNUM 5;逻辑说明all_tables能看到当前用户有权访问的所有表owner字段直接告诉你这张表属于谁。SHOW USER确认当前会话身份。第三句用模式名前缀强制访问真实表绕开同义词依赖能直观判断问题出在对象缺失还是权限缺失。参数说明Oracle 对无引号对象名默认存储为大写所以WHERE table_name EMP必须用大写写emp查不到。ROWNUM 5限制返回行数避免大表全量输出。4.3 现象PL/SQL 中文注释乱码编译直接报错现象把存储过程脚本导入 SQL*Plus窗口里中文注释全变成问号CREATE PROCEDURE编译报字符集相关错误。原因这是客户端字符集和数据库字符集不一致典型的两头不对齐。数据库装的是AL32UTF8客户端 SQL*Plus 却按ZHS16GBK解释脚本字节流两边一对拼就出乱码。解决先查数据库端字符集SELECT VALUE FROM V$NLS_PARAMETERS WHERE PARAMETER NLS_CHARACTERSET;然后设置客户端环境变量让两边一致。假如数据库是AL32UTF8Windows 环境变量里加NLS_LANGAMERICAN_AMERICA.AL32UTF8逻辑说明NLS_LANG告诉 SQL*Plus 客户端应该按什么编码解释输入流设置成和数据库一致后中文注释和字符串字面量才能原样入库。如果源码文件本身是 GBK 编码而数据库是 AL32UTF8最直接的路径是把文件另存为 UTF-8 再执行。参数说明AMERICAN_AMERICA是语言和地区片段可以换成SIMPLIFIED CHINESE_CHINA但关键是最后一个点号后面那段字符集名称必须和数据库一致。这类字符集问题表面看着像玄学本质是编码声明没有对齐。4.4 现象创建表空间时提示文件不可用或路径不存在现象执行CREATE TABLESPACE报ORA-01119或ORA-27040数据文件路径对不上。原因Windows 上最常见是路径带了中文目录或者盘符不存在Linux 上是目录没建或系统用户对目录没有写权限。另一个隐蔽点是上次失败会话占用了同名.DBF文件的句柄文件还没释放。解决先确认目录存在且权限正确再执行创建mkdir -p /u01/app/oracle/oradata/orcl chown oracle:oinstall /u01/app/oracle/oradata/orclCREATE TABLESPACE user_ts DATAFILE /u01/app/oracle/oradata/orcl/user_ts01.dbf SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE 1G;逻辑说明Linux 下数据文件目录必须由运行 Oracle 的系统用户有写权限chown保证属主正确。SIZE 100M是初始大小AUTOEXTEND ON允许文件自动扩展NEXT 10M是单次扩展步长MAXSIZE 1G是上限。参数说明MAXSIZE一定要给否则文件可以无限增长直到把磁盘写满。路径不要和已有控制文件指向的路径冲突。遇到文件句柄占用时优先重启数据库实例或用系统命令查占用进程不要直接删文件。5. 把配套源码变成自己的调试利器三个调试接口与一套源码注释习惯这一章不讲新概念只讲怎么把已经跑通的源码转成自己的调试工具。5.1 用 DBMS_OUTPUT 把存储过程变成可控的调试接口书上的存储过程大多是“能跑就行”的状态报错时很难判断执行到哪一步。我习惯把源码复制一份在关键位置插入输出语句SET SERVEROUTPUT ON; CREATE OR REPLACE PROCEDURE debug_emp_info (p_deptno IN NUMBER) AS v_count NUMBER; BEGIN DBMS_OUTPUT.PUT_LINE(进入过程参数: || p_deptno); SELECT COUNT(*) INTO v_count FROM emp WHERE deptno p_deptno; DBMS_OUTPUT.PUT_LINE(查到行数: || v_count); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(错误: || SQLERRM); END; /逻辑说明SET SERVEROUTPUT ON是让 SQL*Plus 把输出打到屏幕的开关不开启的话DBMS_OUTPUT的内容会被静默吞掉。过程中每段逻辑后加一条输出报错时一眼就能看出卡在了哪一行。SQLERRM在异常段里返回错误文本比干巴巴的WHEN OTHERS THEN NULL有价值得多。调试完记得把输出行删掉只保留原逻辑。5.2 用执行计划比对绑定变量V$SQL 与 dbms_xplan 的配合源码后半部分的查询实验最值得验证的是绑定变量和字面量 SQL 的解析差异。常见做法是把查询改成绑定变量形式再对比执行计划EXPLAIN PLAN FOR SELECT * FROM emp WHERE deptno :dv_deptno; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);逻辑说明EXPLAIN PLAN FOR不真正执行语句只生成预估执行计划DBMS_XPLAN.DISPLAY把计划输出成可读文本。用:dv_deptno作为绑定变量占位符SQL 文本保持恒定Oracle 就能复用游标避免每次硬解析。参数说明绑定变量必须以冒号开头这是 Oracle 的硬性语法。想确认同一语句在库里的真实执行次数可以配合V$SQL查询SQL_TEXT里包含表名的最新记录这是观察共享池命中率最简单的手段。5.3 源码注释编号习惯让每段实例都能找回出处拿到源码包后我做的第一件事永远是给每个脚本头部加一段注释来源章节、实验目标、依赖的表和序列、以及是否修改过。三个月后回头复习时找一段存储过程的效率会成倍提升。从那以后我每次拿到任何一本书的配套源码都强制自己走一遍先解锁账号、拆章执行、逐段加注释的流程不再一股脑把所有脚本进去就跑路。这个习惯帮我省下的排错时间远比当初多花的半小时注释时间值。希望帮到你。本文还有配套的精品资源点击获取
返回列表