存储过程开发指导
目 录
1. 存储过程命名规则.......................................................................................................... 5
2. 排版............................................................................................................................... 6
3. 注释............................................................................................................................... 8
4. 标识符命名..................................................................................................................... 9
5. 编码规范....................................................................................................................... 10
6. 常用技术....................................................................................................................... 11
7. 例子.............................................................................................................................. 13
1. 存储过程命名规则
存储过程模板包:
<业务名>Vx.xDxx0_SP.zip
p_<业务名>_<功能简写>_<业务键>.sql*
<业务名>存储过程说明书.lwp //详细描述存储过程的功能、接口参数、基本处理流程
存储过程包:
<业务名>VxxDxx[IFN]_SPVx.x.zip
p_<调用业务|ASE名>_<功能简写>.sql*
VDD文件:
<业务名>VxxDxx[IFN]_SPVx.x.x.lwp
版本配套表中业务一栏要写明所属业务、所有被充值业务的版本号。对各存储过程的使用方法要说明清楚。写清版本使用的局点。
网上可用文档包:
<业务名>VxxDxx[IFN][_被充值业务名]_SPVx.x_DOC.zip
<历史VDD或readme文档>*
[<其它面向用户的指导文档>*]
测试文档包:
<业务名>VxxDxx[IFN] [_被充值业务名]_SPVx.x_测试文档.zip
<产品名>[<版本号>]<业务名>VxxDxx[IFN][_被充值业务名]_SPVx.x单元测试计划.lwp
<产品名>[<版本号>]<业务名>VxxDxx[IFN][_被充值业务名]_SPVx.x单元测试报告.lwp
开发过程文档:
<业务名><业务名>VxxDxx[IFN][_被充值业务名]_SPVx.x_过程文档.zip
<评审报告|检视报告|走读报告|CheckList>*
代码规模统计表.123
<CCB任务书|SOW任务书>
《3-10人月小业务项目度量表》,填写“详细设计阶段”、“编码阶段”、“单元测试阶段”和“集成测试阶段”四行的内容。
2. 排版
规则1:程序块要采用缩进风格编写,缩进的空格数为4个。
if (t_susestate = '1') then
let o_sreturncode = '01'; --缩进4个空格
end if
规则2:相对独立的程序块之间、变量说明之后必须加空行。
规则3:select后的列名或where后的条件如果太长要分行写。长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。如where后的条件中有and和or,划分行的时候以or来划分。
规则4:循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。
规则5:不允许把多个短语句写在一行中,即一行只写一条语句。
规则6:if、foreach、while等语句自占一行。
规则7:对齐只使用空格键,不使用TAB键。
规则8:在两个以上的关键字、变量、常量进行对等操作时,它们之间的操作符之前、之后或者前后要加空格;进行非对等操作时,后不应加空格。
(1) 逗号、分号只在后面加空格。如columnname1, columnname2, 在逗号之后加一个空格。
(2) if、foreach、while等与后面的括号间应加空格,使if等关键字更为突出、明显。
如:if (t_susestate = '1') then 。 在if后加空格,在then之前加空格。
规则9:写SQL语句要分行写,关键字要放在行首。如果select后的列名每行不能超过5个。into后的变量同样要分行写,而且每行变量的个数与每行表列名的个数相同。
如:select scolumnname1, scolumnname2
into t_svarname1, t_svarname2
from tablename
where scolumnname = condition;
规则10:SQL语句同样采用缩进的方式。以第一个关键字为准,后面的关键字的最后一个字母和第一个关键字的最后一个字母对齐。
如:select scolumnname1, scolumnname2
into t_svarname1, t_svarname2
from tablename
where scolumnname = condition;
关键字select的“t”、关键字into的“o”、关键字from的“m”和关键字where的“e”对齐。
3. 注释
规则1:边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。特别是在拷贝粘贴后,在修改了代码后一定要同时修改注释。
规则2:注释的内容要清楚、明了,含义准确,防止注释二义性。
规则3:避免在注释中使用缩写,特别是非常用缩写。如果缩写的注释让人更糊涂,那还不如不要这个注释。
规则4:注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如果放于上方则需与其上面的代码用空行隔开,与被注释的代码相邻,不要用空行隔开。
规则5:存储过程里传入传出参数要注明变量含义,如果变量可能的值不多,如标志位变量,在注释中列出值的含义。标志存储过程是否执行成功的标志位o_sreturncode,要列出所有可能值的含义。
规则6:注释与所描述内容进行同样的缩排。
规则7:对变量的定义和分支语句(条件分支、循环语句等)必须编写注释。
4. 标识符命名
规则1:标识符命名采用前缀1_标识符名的格式
前缀有:i、s; i表示整型,s表示字符串型。
如:define s_usestate char(1); --表示变量是字符型,存储过程内部使用变量
规则2:标志符除了前缀和后缀外,其余部分和业务或数据库标识符一致。对数据库表的列名同样采用全部小写的方式,不要采用大小写混排的方式,保证命名规则的一致。
规则3:对于变量命名,禁止取单个字符(如i、j、k...)和temp1,temp2等变量。建议除了要有具体含义外,还能表明其变量类型。
规则4:存储过程命名符合命名规范p_<调用业务|ASE名>_<功能简写>_<业务键>,存储过程名称最长允许18位
规则5:存储过程变量定义必须在存储过程的前面,存储过程内部不允许定义变量。如果有定义了但没有引用的变量必须要删除。
5. 编码规范
规则1:在存储过程中如果有使用事务,则必须有以下异常处理流程
on exception
on exception in(-255)
let s_returncode = ’12’;
return s_returncode;
end exception
rollback work;
let s_returncode = ’12’;
return s_returncode;
end exception
异常处理流程默认开始了事务,然后增加对rollback work执行失败的处理。
如果没有使用事务,异常处理流程:
on exception
let s_returncode = ’12’;
return s_returncode;
end exception
出现过问题的案例:
on exception in (-206, -239, -217, -696) 红色是画蛇添足的内容。
let s_returncodeo = '12';
rollback work;
return s_returncodeo;
end exception
on exception in (10000)
let s_returncodeo = '01';
rollback work;
return s_returncodeo;
end exception
on exception in(-206,-239,-217,-696)表示只有发生括号内部列出的错误号才会执行后续的异常处理流程。如果错误号没有在定义范围内,那存储过程直接结束。就有可能导致事务没有结束,后续的SQL语句全部在事务内,占用大量系统资源,进而影响呼叫。
规则2:数据库操作(select,update,delete)后要判断数据库操作是否成功,判断方式:t_irowcount = dbinfo('sqlca.sqlerrd2');
规则3: 如果存储过程中有更新数据库数据的操作(如:update,delete,insert),在这些操作之前要有begin work; 存储过程正常返回之前要有commit work; 存储过程返回错误之前要有rollback work;
规则4:返回变量要设置默认值。select操作时,如果没有读取到数据,会把变量赋值为null,这时要重新给返回值赋值。
规则5:if后的条件内容要用括号括起来,使条件更明显。
规则6: 存储过程里的SQL语句一定要考虑到能否用上索引。避免出现SQL语句用不上索引,导致效率低下的情况。
规则7: 用update更新卡余额的时候,update不能采用直接赋值的方式,必须采用直接加的方式:nacccountleft = naccountleft + i_iaccountleft
规则8:在一个存储过程里,只有必要时才使用事务,而且要求保证存储过程每次执行只能有一个事务生效。
1、如存储过程内部只有select语句,或者没有sql语句,则不需要使用事务。
2、在开始事务之前不能使用事务开始标志位。
如: let s_workflag = ‘1’;--不需要使用该标志位,减少存储过程复杂度。
begin work;
if (s_workflag = ‘1’) then
rollback work;
end if;
3、如果存储过程开始了事务,则必须在存储过程内部结束事务。否则会因为事务占用系统资源而严重影响呼叫。
规则9:正式归档的存储过程一定不能放开调试信息,否则会影响系统性能。
如:--set dubug file to “log.log”;
--trace on;
规则10: 存储过程归档之前必须使用存储过程检查工具检验通过后才能正式归档。
检查工具(后续提供):
规则11: 开发多次加载的存储过程,除了修改存储过程名的业务键外,还需要修改存储过程内部对应的表名。因为多次加载的业务表名会根据业务键修改。
如给业务键2301的CCS卡解锁的存储过程名称为p_vc_unlock_2301;存储过程内部访问的表为:basetab_2301;
规则12:一个存储过程的大小不能超过64K(informix数据库的限制)。存储过程如果超过64K,则拆分该存储过程,然后用call调用拆分的存储过程实现。
call的语法:
call proc_name(in_para_list) returning out_para_list / out_result_set;
拆分方式1:如果是在原有存储过程基础上新增业务键的处理,而且时间比较紧的情况下,则可以把新增的业务键处理单独作为一个存储过程,然后在主存储过程调用该存储过程实现。
如:p_vc_identify_in.sql存储过程新增业务键2308的处理,则新增一个存储过程p_vc_inauth_2308.sql处理业务键2308,然后在p_vc_identify_in.sql存储过程中调用该存储过程实现。
拆分方式2:如果是新开发存储过程,或者开发的时间允许的情况下,要把存储过程中对每个业务键的处理都单独作为一个存储过程,然后在主存储过程中分别根据不同的业务键调用不同的存储过程。
如:p_vc_identify_in.sql要处理业务键2301、2302、2303,则把2301、2302、2303的处理单独作为一个存储过程p_vc_inauth_2301.sql、p_vc_inauth_2302.sql、p_vc_inauth_2303.sql,然后在p_vc_identify_in.sql存储过程里根据不同的业务键调用不同的存储过程。
规则13: 用户自定义的异常处理流程不能写入事务操作,必须保证在调用自定义异常出口前完成事务的处理
如: on exception in (10000)
let s_returncodeo = '01';
rollback work; --不能在自定义异常处理流程写入事务操作。
return s_returncodeo;
end exception
6. 常用技术
1、取系统当前时间,并转换为字符串类型
let t_scurrentdate = to_char(current, '%Y%m%d');
t_scurrentdate 为char(8),current为系统变量。
2、更新有效期方法:
let o_sservicestop = to_char((to_date(o_sservicestop, '%Y%m%d') + (i_iperiodlast) units DAY), '%Y%m%d');
先把原来的o_sservicestop转换为date型,加上延长天数后,再转换为char型。
(说明: 存储过程提供的日期相加,如果是相加月,相加年,只是单纯的数字相加,并不会根据大小月、闰年进行自动调整。会导致计算日期之后得到非法日期。如20040131,加一个月,存储过程得到的结果是20040231这样一个非法的日期)
3、取子字符串的方法:
方法1:tempstr = substr(tempstr,n1,n2);
n1表示从第几位开始,n2表示字符串长度。如果n2省略,则取后面所有字符串
(说明: INFORMIX存储过程中使用SUBSTR()在高CAPS下会出错问题,概率为万分之5左右。)
方法1:tempstr = tempstr[n1,n2];
n1表示从第几位开始,n2表示第几位结束。如果n2省略,则取一个字符。
如tempstr=’12345678’
tempstr1 = tempstr[3,4]
最后得到的结果是’34’。
4、打开存储过程调试信息的方法:
set debug file to "filename";
trace on;
trace off;
filename文件中保存调试信息。
提醒:在存储过程归档之前一定要注释掉放开调试信息的语句。
5、在存储过程里,SQL语句要使用order by,SQL语句要用foreach包括。
foreach
select first 1 scolumnname
into s_columnname
from tablename
where (scolumnname2 = condition )
order by scolumnname desc //说明:order by字段必须在select中存在。
exit foreach;
end foreach;
6、取变量字符串长度
let t_ipinlength = length(s_pinnumber);
7、连接两个字符串
let s_accountnumber = s_prefix || s_accountnumber;