当前位置:网站首页>给测试小姐姐的第三封信 | ORACLE存储过程知识分享和测试说明
给测试小姐姐的第三封信 | ORACLE存储过程知识分享和测试说明
2022-07-27 05:11:00 【神芷迦蓝寺】
1 兵马未动 粮草先行
1.1 引言
文章基于Oracle数据库简单介绍了存储过程(以下简称存过)的定义,调试,运维等相关知识,使能达到对存过的总体认知及部分掌握。文章主体共分为三部分,即存过的相识相知,开发测试以及问题总结,其中详细描述了存过常见的测试类型和测试流程,最后附上附注信息方便日常问题的快速定位和解决。
1.2 语言工具
需用到的语言工具与版本
| 名称 | 版本 | 用途 |
|---|---|---|
| kettle | 7.1 | ETL工具 |
| ORACLE | 11.2.0 | 数据库 |
| ojdbc6.jar | 6 | 连接Oracle的必备jar包 |
| pl/sql(Navicat) | 10.0.5 | ORACLE开发工具 |
| Tips | 部分语言工具向下兼容 |
2 知己知彼 百战不殆
2.1 存过定义
存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,其本质就是数据库SQL 的代码封装与重用。
2.2 优缺点
优点:
- 执行速度快——存储过程只在创建时进行编译,以后每次执行存储过程都不需要重新编译
- 减少网通量——当对数据库进行复杂操作时,如对多个表进行insert、update可集合事务批量一起运行
- 提高复用性——存储过程可以重复使用,提高了可重用性
- 可维护性高——更新存储过程通常比更改、测试以及重新部署程序集需要较少的时间和精力
- 高安全可靠——数据库本身的权限机制决定了他的安全性
缺点:迁移难,可复制性不高,开发难度大,虽然只是简单列了这三个缺点,但是就这三个缺点却是大据时代下存过逐渐被淘汰的最根本最致命原因。
2.2 创建
上面铺垫了那么多,现在我们开始真正来了解这个可爱的存储过程
2.3.1. 创建存过
任何美丽的语言都是从一个Hello World开始
CREATE OR REPLACE PROCEDURE testMyProcedure AS --创建/替换一个存过
BEGIN
dbms_output.put_line('Hello World'); --在这里输入sql集合,每个sql模块用;分割
END; 如同多复杂的sql其本质都是select * from table一般,往后的存过无论多复杂,框架就是上图的样子,在begin和end之间写你想要实现的sql集合和其他开发语言一样,sql遵循的运行方式也是由上而下,由内而外。
2.3.2. 创建存过包
试想一下,存过明明是所有sql的集合,为什么还要再创建一个所有存过的集合即存过包pck来呢?因为每一个存过都是你想实现的需求场景,但是在某些特定环境下,没必要把所有场景都一一实现,所有的场景集中在一个存过里,既浪费了资源又加重了代码冗余。所以这里出现了一个存过包的概念,起到一个分类汇总和特定调用的作用。
理清了这个概念,我们开始新建一个存过包,存过包是我们日常测试最常见的一种类型
create or replace package pkg_etl_fgjj -- 创建存过包
is
-- 存过一, 后面的p_date和p_tenant_code是传参,在下文调用那里会详解
procedure sp_pro_sectors1(p_date varchar2,p_tenant_code varchar2);
-- 存过二
procedure sp_pro_sectors2(p_date varchar2);
-- 存过三 开发存过的规范是即使该存过不需要入参,也要传入p_date时间,用来日志记录
procedure sp_pro_sectors3(p_date varchar2);
end; -- end代表存过包的声明结束了
/ -- /属于规范,必须要,用于合脚本分割
-- 创建存过包体,即存过包里每个存过的具体内容
create or replace package body pkg_etl_fgjj IS
-- 声明存过一,需要注意的是在存过包里,声明创建存过无需再加create,直接procedure xxx即可
PROCEDURE sp_pro_sectors1 (p_date varchar2,p_tenant_code varchar2)
-- 声明变量,赋值用 := ,声明时需加类型
IS v_sysdate DATE := SYSDATE;
v_sqlerrm VARCHAR2 ( 1000 );
BEGIN
-- 包含的sql集合,这里是重点测试的地方,其他地方都是框架,一般是不变的
merge into pro_sell_map p xxxxxxxxx;
execute IMMEDIATE 'xxxxxxxxxxxx';
-- 开发规范,要求每个存过必须有日志留存,无论成功与否
insert into procedure_log
values (to_number(p_date),'pkg_etl_fgjj.sp_pro_sectors','1',v_sysdate,sysdate,'');
-- 存过报错后,提交异常与回滚,并写进日志,这一块属于开发框架规范,一般不会变
commit;
EXCEPTION
WHEN others THEN
rollback;
v_sqlerrm := sqlerrm;
INSERT INTO procedure_log t
VALUES
( to_number( p_date ), 'pkg_etl_fgjj.sp_pro_sectors', '2', v_sysdate, SYSDATE, v_sqlerrm );
commit;
raise;
end; -- end代表存过1的声明结束了
-- 限于篇幅,存过2和3不再赘述,需要注意这里的入参和上面的入参需一致
PROCEDURE sp_pro_sectors2 (p_date VARCHAR2) IS .... END
PROCEDURE sp_pro_sectors3 (p_date VARCHAR2) IS .... END
end; -- end代表存过包体的声明结束了
/2.4.打包
我们打包运行是规范产品化的,由专用打包工具进行打包在一个sql文件里,然后在Oracle命令行里直接@sql文件名运行
如果是单独运行某一存过包,可以在命令行里@这个文件名,或者打开sql窗口,把文件里的内容拷贝出来,放sql窗口里全选运行
2.5.调用
存过的调用比较简单,有两种调用方式
-- 运行单存过
-- 1
BEGIN
testMyProcedure;
END;
-- 2
CALL testMyProcedure();
-- 运行存过包里的存过,一般用的都是这种
-- 3
BEGIN
pkg_etl_fgjj.sp_pro_sectors1('20220526','FGJJ');
END;
-- 4
CALL pkg_etl_fgjj.sp_pro_sectors1('20220526','FGJJ');2.6.查看编辑
针对已经打包好的存过包如何进行查看和编辑呢,可以选择在plsql工具里进行:Packages—存过包—右键查看/编辑规范与体—对应存过

如果是编辑后,想立即生效可以点击运行,就可以把编辑好后的存过立即生效了。Tips: 这种方法最简单但也很危险,尤其是在生产环境,所以我们尽量点击查看( 而不是编辑) 就可以了,找出对应问题测试通过之后再更改生效
3. 势者 因利而制权也
测试是一门学问,其最终的要义是测试对象能成功运行,能正确运行,能快速运行,不过拟合,兼通万境。针对存储过程测试来说,推荐测试流程为
3.1 明确需求
如某一现场要求开发个性化存过,实现二级市场替换为wind分类,那么我们测试的最终目标就明确了,运行你的存过后,基金的二级市场能正确替换为对应的二级市场。当然这些都是测试的必备功底,不再赘述
3.2 通断测试
现在的存过一般都是在现有的存过包基础上进行增量开发,一般不会出问题,但偶尔可能会有兼容性问题,比如少写了分号,end等,我们可以把整个pck进行打包运行,然后按照效能上开发者的调用说明,调用该存过,能否能正常和快速运行,如果不能,则属于是易现缺陷了
3.3 成果测试
测试该存过调用后能否实现需求,是否是过拟合,如写死了租户号,如明明是要求改公募基金,却没指定FUND等等
3.4 其他测试
测试该存过的一些细节规范,这里可参见2.3.2,常见的如:
- 命名规范:不与其他同类型存过命名类似,过于天马行空
- 日志规范:存过最后未往procedure_log表里插入日志,成功与否都要
- 范围规范:在创建包和创建包体结尾是否都有/
4 静以幽 正以治
存过打包是秒打的,但这个时候还无法确定是否是正常的,可以通过call 调用来测试,或者按照2.6查看那里点开,系统也会精准提示

下面附录几个Oracle存过常见报错
- ORA-00001 dup_val_on_index 唯一索引/主键对应有重复值
- ORA-06511 cussor_already_open 重复打开已打开的游标
- ORA-01722 invalid_number 非法字符串转换数字类型
- ORA-01403 no_data_found 执行select into未返回行
- ORA-01422 too_many_rows 执行select into返回多行
- ORA-01476 zero_divide 0作为了除数
- ORA-06502 value_error 赋值字段超长
- ORA-06500 storage_error 内存溢出
- ORA-00051 timeout_on_resource 等到资源超时
当然我们已与百度达成了战略合作关系,出现ORA错误可以直接百度
边栏推荐
猜你喜欢
随机推荐
Differences between IsNaN and number.isnan in JS
怎么开立普通商品期货账户
期货开户之前要先谈好手续费
How to use for..Of to traverse objects in JS
一本通1319——排队接水
自我理解思考
每周学习总结
洛谷超级玛丽游戏
JS中数组的遍历方法有哪些
布局的搭建及天气预报的显示
XSS知识点
「PHP基础知识」字符串型(string)的使用
Fortex方达发布电子交易生态体系 与客户共享共赢
Introduction to C language functions
Page configuration
First acquaintance with C language - first acquaintance with pointer
The difference between deep copy and shallow copy in JS
维持登录,路由跳转
JS中forEach和map方法有什么区别
Usage and differences among let, const and VaR





![[极客大挑战 2019]FinalSQL 1](/img/a7/857d47639fcb38e0055a2444206b8c.png)



![[CISCN2019 华东南赛区]Web11 1](/img/94/61ad4f6cbbd46ff66f361462983d7a.png)