DB2 存储过程开发最佳实践
- 格式:doc
- 大小:150.00 KB
- 文档页数:14
DB2 9.5 SQL Procedure Developer第1 部分: SQL Procedural Language 入门变量声明SQL 过程允许使用本地变量赋予和获取SQL 值,以支持所有SQL 逻辑。
在SQL 过程中,在代码中使用本地变量之前要先进行声明。
清单1 中的图演示了变量声明的语法:SQL-variable-name定义本地变量的名称。
该名称不能与其他变量或参数名称相同,也不能与列名相同。
图1 显示了受支持的DB2 数据类型:图1. DB2 数据类型DEFAULT值–如果没有指定,在声明时将赋值为NULL。
下面是变量声明的一些例子:∙DECLARE v_salary DEC(9,2) DEFAULT 0.0;∙DECLARE v_status char(3) DEFAULT ‗YES‘;∙DECLARE v_descrition VARCHAR(80);∙DECLARE v1, v2 INT DEFAULT 0;请注意,从DB2 version 9.5 开始才支持在一个DECLARE 语句中声明多个相同数据类型的变量。
数组数据类型SQL 过程从9.5 版开始支持数组类型的变量和参数。
要定义一个数组类型的变量,需要先在数据库中创建该类型,然后在过程或应用程序中声明它。
数组是临时的值,可以在存储过程和应用程序中操纵它,但是不能将它存储到表中。
DB2 支持以下创建数组数据类型的语法:数组类型的名称应该用模式加以限定,并且在当前服务器上应该是惟一的。
LONG VARCHAR、LONG VARGRPAHIC、XML 和用户定义类型不能作为数组元素的数据类型。
请注意,整数―constant‖ 指定数组的最大基数,它是可选的。
数组元素可以通过ARRAY-VARIABLE(subindex) 来引用,其中subindex 必须介于1 到数组的基数之间。
现在可以在SQL 过程中使用这个数据类型:DB2 支持一些操作数组的方法。
DB2常用的命令1.启动数据库db2start2.停止数据库db2stop3.连接数据库db2 connect to database user db2admin using pwd(注:database为数据库名)4.读数据库管理程序配置db2 get dbm cfg5.写数据库管理程序配置db2 update dbm cfg using 参数名参数值6.读数据库的配置db2 connect to o_yd user db2 using pwddb2 get db cfg for o_yd7.写数据库的配置db2 connect to o_yd user db2 using pwddb2 update db cfg for o_yd using 参数名参数值8.关闭所有应用连接db2 force application alldb2 force application ID1,ID2,,,Idn MODE ASYNC(db2 list application for db o_yd show detail)9.备份数据库db2 force application alldb2 backup db o_yd to d: (db2 initialize tape on \\.\tape0) (db2 rewind tape on \\.\tape0) db2 backup db o_yd to \\.\tape010.恢复数据库 db2 restore db o_yd from d: to d: db2 restore db o_yd from \\.\tape0 to d:11.绑定存储过程 db2 connect to o_yd user db2 using pwd db2 bind c:\dfplus.bnd 拷贝存储过程到服务器上的C:\sqllib\function目录中12.整理表 db2 connect to o_yd user db2 using pwd db2 reorg table ydd db2 runstats on table ydd with distribution and indexes all 13.导出表数据db2 export to c:\dftz.txt of del select * from dftzdb2 export to c:\dftz.ixf of ixf select * from dftz14.导入表数据import from c:\123.txt of del insert into ylbx.czyxxdb2 import to c:\dftz.txt of del commitcount 5000 messages c:\dftz.msg insert into dftzdb2 import to c:\dftz.ixf of ixf commitcount 5000 messages c:\dftz.msg insert into dftzdb2 import to c:\dftz.ixf of ixf commitcount 5000 insert into dftzdb2 import to c:\dftz.ixf of ixf commitcount 5000 insert_update into dftzdb2 import to c:\dftz.ixf of ixf commitcount 5000 replace into dftzdb2 import to c:\dftz.ixf of ixf commitcount 5000 create into dftz (仅IXF)db2 import to c:\dftz.ixf of ixf commitcount 5000 replace_create into dftz (仅IXF)15.执行一个批处理文件db2 –tf 批处理文件名(文件中每一条命令用;结束)16.自动生成批处理文件 建文本文件:temp.sql select 'runstats on table DB2.' || tabname || ' with distribution and detailed indexes all;' from syscat.tables where tabschema='DB2' and type='T';db2 –tf temp.sql>runstats.sql17.自动生成建表(视图)语句在服务器上:C:\sqllib\misc目录中db2 connect to o_yd user db2 using pwddb2look –d o_yd –u db2 –e –p –c c:\o_yd.txt18.其他命令grant dbadm on database to user bb19select * from czyxx fetch first 1 rows only20db2look –d ylbx –u db2admin –w –asd –a –e –o a.txt21. 显示当前用户所有表list tables22.列出所有的系统表list tables for system23.查看表结构db2 describe select * from user.tablesDB2常用的SQL语句1、组合语句执行BEGIN ATOMIC表达式1 分号空格/回车表达式2 分号空格/回车END2、应该限制访问权限的表(应该撤销这些表PUBLIC SELECT访问权)SYSCAT.DBAUTHSYSCAT.TABAUTHSYSCAT.PACKAGEAUTHSYSCAT.INDEXAUTHSYSCAT.COLAUTHSYSCAT.PASSTHRUAUTHSYSCAT.SCHEMAAUTH比较有用的目录表SYSCAT.COLUMNS:包含每一行对应于表或视图中定义的列SYSCAT.INDEXCOLUSE:包含每一行包含的所有列SYSCAT.INDEXES:包含每一行对应于表或视图中定义的每个索引SYSCAT.TABLES:所创建每个表,视图,别名对应其中一行SYSCAT.VIEWS:所创建每个视图对应其中一行或几行通过索引保持数据唯一性:CREATE UNIQUE INDEX INDEXNAME ON TABLE (COLUMN)消除重复行:SELECT DISTINCT COLUMN FROM TABLE3、DB2关于时间的一些函数得到当前时间的年份、月份、天、小时等等:YEAR (current timestamp)MONTH (current timestamp)DAY (current timestamp)HOUR (current timestamp)MINUTE (current timestamp)SECOND (current timestamp)MICROSECOND (current timestamp)分别得到当时的日期和时间DATE (current timestamp)TIME (current timestamp)关于时间的一些计算:current date + 1 YEARcurrent date + 3 YEARS + 2 MONTHS + 15 DAYScurrent time + 5 HOURS - 3 MINUTES + 10 SECONDS计算两个日期之间有多少天:days (current date) - days (date(’1999-10-22′))得到去除毫秒的当前时间:CURRENT TIMESTAMP - MICROSECOND (current timestamp) MICROSECONDS将时间转换成字符串:char(current date)char(current time)char(current date + 12 hours)将字符串转换成时间:TIMESTAMP (’2002-10-20-12.00.00.000000′)TIMESTAMP (’2002-10-20 12:00:00′)DATE (’2002-10-20′)DATE (’10/20/2002′)TIME (’12:00:00′)TIME (’12.00.00′)注意:在DB2的命令编辑器中可以输入SQL语句和DB2中的内部命令。
OLTP类应用系统之DB2数据库优化最佳实践本文所涉及的优化技巧均建立在您的数据库物理架构已经设计完成后而为了保证您的应用有最佳表现所必须做的后续优化工作。
下面这些有关数据库配置调优的技巧将使您在OLTP 环境中取得非常好的性能,同时使您能够避免显而易见的“陷阱”。
在配置参数中,数据库管理器配置参数需要重新启动数据库管理器,而为了使更改生效,大多数数据库配置参数都要求应用程序重新连接到数据库。
这里要优化的配置参数如下所示:一、配置缓冲池大小缓冲池命中率表明数据库管理器不需要从磁盘装入页(即该页已经在缓冲池中)就能处理页请求的时间百分比。
缓冲池的命中率越高,使用磁盘 I/O 的频率就越低。
按如下计算缓冲池命中率:db2pd -d dbname -bufferpools这个计算考虑了缓冲池高速缓存的所有页(索引和数据)。
理想情况下,该比率应当超过95%,并尽可能接近100%。
要提高缓冲池命中率,请尝试下面这些方法:1) 增加缓冲池大小#db2 "alter bufferpool bpname immediate size 40000"2) 考虑分配多个缓冲池,如果可能的话,为每个经常被访问的大表所属的表空间分配一个缓冲池,为一组小表分配一个缓冲池,然后尝试一下使用不同大小的缓冲池以查看哪种组合会提供最佳性能。
#db2 "create bufferpool bpname SIZE 200 PAGESIZE 8K"如果已分配的内存不能帮助提高性能,那么请避免给缓冲池分配过多的内存。
应当根据取自测试环境的快照信息来决定缓冲池的大小。
二、配置日志缓冲区大小(LOGBUFSZ)LOGBUFSZ 是一个数据库配置参数。
它是用于日志缓冲区的参数。
它允许您指定数据库共享内存的大小以用作在将日志记录写到磁盘之前这些记录的缓冲区。
当下列事件之一发生时会将日志记录写到磁盘:1) 事务提交;2) 日志缓冲区已满;3) 其它某个内部数据库管理器事件发生时。
DB2 最佳实践: 性能调优和问题诊断最佳实践,第1 部分性能调优从配置和监控开始2009 年 3 月12 日本系列介绍了DB2 系统性能的最优方法,分两部分。
第一部分首先介绍为了达到良好性能,我们如何从软硬件配置方面来保障,紧接着讨论了在多种在操作和故障诊断的情况下,有助于我们了解系统性能的监控方法。
第 2 部分我们介绍在出现性能问题时如何逐步地、有条不紊地去处理它们。
内容提要大多数DB2 系统都经过了性能的演变。
首先,不论出于硬件还是软件的观点,该系统首先要能被配置。
在多数情况下,这将成为系统在实施后如何运行的基础。
其次,系统一经发布,勤勉的数据库管理员(DBA)将监控系统的性能,来监测任何可能的开发问题。
如果发现任何问题,我们就进入下一个阶段- 故障诊断阶段。
每个阶段都是基于上一阶段,如果没有适当的准备,我们极有可能需要处理比较困难的问题。
本文介绍了DB2 系统性能的最优方法。
我首先涉及到一些有助于我们确保良好软硬件性能的重要原则。
然后我们讨论多种在操作和故障诊断的情况下,有助于我们了解系统性能的监控方法。
最后,尽管我们做了最好的准备,性能问题仍然可以降临到我们身上,我们讨论如何逐步地处理它们,并有条不紊的进行。
回页首简介任何形式的性能问题都将严重影响并降低一个系统对你组织的价值、削弱业务能力、服务中断、以及增加管理开销。
所有这些都会提升总的拥有成本。
缺乏对系统配置的基本原则,监视和性能故障诊断可能导致不同程度的性能低下,并且降低对于组织的价值。
因此,在前期花些时间去考虑基本的配置指导方针和建立健全的系统监控这样的做法,将使你对处理许多可能出现的典型性能问题,有充分的准备。
并使数据服务器得以高性能运行,以提高投资回报率。
回页首第一步:从配置上实现性能良好像InfoSphere 平衡的仓库(BW)这类的DB2 部署类型,或者那些在SAP 系统之内的系统,配置都是高度确定的。
在BW 案例中,像CPU 个数、内存对 CPU 的比率、硬盘的个数和配置这样的硬件因素,以及在预先指定版本的基础上,详尽的测试,以确定最优配置。
db2 调用存储过程【原创版】目录1.DB2 简介2.存储过程简介3.DB2 调用存储过程的方法4.调用存储过程的实例5.存储过程的优点正文【1.DB2 简介】DB2 是一种关系型数据库管理系统,由 IBM 公司开发。
它广泛应用于企业级数据管理,提供高效、安全、可靠的数据存储和处理能力。
DB2 支持多种平台,如 Windows、Linux、Unix 等,可以满足不同用户的需求。
【2.存储过程简介】存储过程是一种预编译的 SQL 语句,它封装了一些逻辑操作,可以减少网络传输量,提高数据库性能。
存储过程可以用于实现复杂的业务逻辑,降低应用程序的开发难度。
【3.DB2 调用存储过程的方法】在 DB2 中,可以通过以下几种方法调用存储过程:(1)使用 CALL 语句:CALL<存储过程名>([参数 1, 参数 2,...])。
(2)使用 EXECUTE 语句:EXECUTE<存储过程名>([参数 1, 参数2,...])。
(3)使用动态 SQL:使用 PREPARE 和 EXECUTE 语句动态创建和执行存储过程。
【4.调用存储过程的实例】假设有一个名为“get_employee_list”的存储过程,它用于查询员工表中的所有记录。
可以使用以下代码调用该存储过程:```sqlCALL get_employee_list();```【5.存储过程的优点】存储过程具有以下优点:(1)封装性:存储过程可以将业务逻辑封装起来,降低应用程序的复杂度。
(2)性能:存储过程可以减少网络传输量,提高数据库性能。
(3)安全性:存储过程可以实现数据访问控制,保护数据的安全。
10.1 日常运维工具概述Runstats是run statistics的缩写,意思是收集统计信息,目的是为DB2优化器提供最佳路径选择;Reorg是重组的意思,目的是减少表和索引在物理存储上的碎片,提供性能;Reorgchk是重组前的检查Rebind是对一些包、存储过程或静态程序进行重新绑定。
几个工具的执行流程:首先通过Runstats收集表和索引的统计信息,然后执行Reorg重组,如果有必要则执行,然后再次收集统计信息。
最后,对于静态语句、存储过程等,执行Rebind绑定。
10.2 Runstats在系统运行一个查询的时候,优化器需要决定用某种方式来访问数据。
只有当DB2对表中的数据有一个大概的了解,才能知道每一步操作大约需要处理多少数据,返回多少行。
当优化器了解了这些信息后,就会根据一系列的运算,判定出各种访问途径所需要消耗的资源,然后从中选择一个消耗资源最少的方法。
最普通的Runstats就是统计表和索引中有多少行数据,有多少不同的数值。
Runstats命令使用DISTRIBUTION参数手机数据分布。
数据分布分为两种,一种叫做频率采样(Frequency),一种叫做百分比采样(Quantile)。
当收集数据分布时,两种采样方式都会被收集。
其中频率采样是手页脚内容1机表中拥有相同数量最多的几行,比如10000行数据中9000行为10,然后500行为9,然后100行为8,剩下的部分平均分布。
如果我们制定Frequency为3的话,那么系统就会记录下来有9000行10,500行9,然后100行8,剩下的部分在估算时则假定平均分布。
而百分比采样则是将整个10000行数据分成相等大小的若干段,然后记录每一段的段首和段尾的数值,当需要查询一个数据段时(比如C1>10 AND C1<15),就可以根据每一个数据段的启始数值加上段落的大小,估算出符合查询条件的记录数量。
理论上,数据分布收集的越细致越好。
java调用db2存储过程例子java调用db2存储过程例子1. JAVA 调用db2存储过程最简单的例子:存储过程创建代码:<o:p></o:p>sql 代码1.SET SCHEMA IES ;2.3.Create procedure ies.test()4.NGUAGE SQL6.7.Update t_ryxx set xm =’xy’ where ryxxid=’xm’java 代码1.conn = DbMaster.getConn();2.System.out.println("begin………");3.proc = conn.prepareCall("{call test()}");4.proc.execute();<o:p></o:p>2. Java调用db2带输入参数存储过程的例子:<o:p></o:p>Db2创建存储过程的代码:<o:p></o:p>sql 代码5.Drop procedure ies.test();6.SET SCHEMA IES ;7.Create procedure ies.test(in i_ryxxid varchar(50))NGUAGE SQL9.Update t_ryxx set xm =’xy’ where ryxxid=i_ryxxid10.java 代码11.conn = DbMaster.getConn();12.System.out.println("begin");13.proc = conn.prepareCall("{call test(?)}");14.proc.setString(1,"RY0003");15.proc.execute();16.System.out.println("end:");3.有输入输出参数的代码:创建存储过程的代码:sql 代码17.SET SCHEMA IES ;18.CREATE PROCEDURE IES.test (IN in_ryxxid varchar(50),out out_xm varchar(50))NGUAGE SQL20.21.select xm into out_xm from ies.t_ryxx where ryxxid=in_ryxxid;java 代码22.proc = conn.prepareCall("{ call test(?,?)}");23.proc.setString(1, "011900380103");24.proc.registerOutParameter(2, Types.VARCHAR);25.proc.execute();26.String xm = proc.getString(2);27.System.out.println("end:"+xm);4.带有游标的存储过程(不知道这里的游标什么时候close的。
DB2 HADR最佳实践摘要DB2 High Availability Disaster Recovery (HADR) 是一个简单易用的数据复制特性,该特性为局部和全面站点故障提供一个高可用性(HA)解决方案。
但是,由于用户的需求千差万别,因此不存在绝对理想的HADR 配置。
您的HADR 环境设置、调优和维护决策通常是权衡利弊的结果。
比如,您可能需要在数据库可用性要求和防止数据丢失之间进行权衡。
好消息是,进行权衡并不一定意味着需要以牺牲某项需求为代价。
本文就设置和维护您的HADR 环境提供了一些推荐方法,以帮助您在HADR 提供的保护与性能和成本之间找到平衡点。
本文重点关注以下领域:∙为快速故障转移设置系统∙调优参数以改进网络性能∙调优参数以最小化HADR 相关日志记录对性能的影响∙在HADR 环境中选择适当的表重组方法和负载操作HADR 简介HADR 从一个源数据库(称为主数据库)向一个目标数据库(称为备用数据库)复制数据更改。
由于这是一个无共享架构,每个数据库都使用自己的存储器。
HADR 在主数据库失败时提供快速故障转移。
您还可以在实施更新和实施维护等场景中便捷地转换主数据库和备用数据库的角色,从而将停机时间减至最小。
HADR 用途广泛,并被完全集成到DB2 数据库,不需要任何特殊硬件和软件,使用标准TCP 接口连接主数据库和备用数据库,其设置只需几个数据库配置参数。
HADR 的一个核心原则是:数据库的性能和可用性不能被某些挑战所影响,比如工作负载的突然波动(这影响备用数据库上的日志重放活动量)和服务器或网络失败(这将导致故障转移)。
为实现最优性能而调优您的HADR 解决方案应该遵循一些基本原则,以避免一段时间后出现的潜在问题。
另外,您需要了解几个涉及您的数据库维护行为的HADR 设置项目。
这个最佳实践文档将解决这些问题。
本文着眼于为您设计HADR 基础设施和配置数据库提供指南和推荐方法,从而改进HADR 相关性能,特别是日志记录和故障转移速度。
DB2实验报告一、实验目的本次 DB2 实验的主要目的是深入了解和掌握 DB2 数据库的基本操作和管理功能,包括数据库的创建、表的设计与操作、数据的插入、查询、更新和删除,以及索引和存储过程的使用等。
通过实际操作和实践,提高对数据库原理和技术的理解和应用能力,为今后在数据库相关领域的学习和工作打下坚实的基础。
二、实验环境操作系统:Windows 10DB2 版本:DB2 ExpressC 111开发工具:DB2 Command Line Processor (CLP)、IBM Data Studio三、实验内容及步骤(一)数据库的创建1、打开 DB2 CLP,输入以下命令创建数据库:CREATE DATABASE sample;2、连接到新创建的数据库:CONNECT TO sample;(二)表的设计与创建1、设计了以下两张表:员工表(EMPLOYEE)|列名|数据类型|约束|||||| EMPID | INT | PRIMARY KEY || NAME | VARCHAR(50) | NOT NULL || AGE | INT | CHECK (AGE >= 18) || DEPARTMENT | VARCHAR(50) |工资表(SALARY)|列名|数据类型|约束|||||| EMPID | INT | FOREIGN KEY REFERENCES EMPLOYEE(EMPID) || SALARY | DECIMAL(10, 2) | NOT NULL |2、使用以下命令创建表:CREATE TABLE EMPLOYEE (EMPID INT PRIMARY KEY,NAME VARCHAR(50) NOT NULL,AGE INT CHECK (AGE >= 18),DEPARTMENT VARCHAR(50));CREATE TABLE SALARY (EMPID INT,SALARY DECIMAL(10, 2) NOT NULL,FOREIGN KEY (EMPID) REFERENCES EMPLOYEE(EMPID));(三)数据的插入1、向员工表中插入以下数据:INSERT INTO EMPLOYEE (EMPID, NAME, AGE, DEPARTMENT) VALUES (1, '张三', 25, '研发部'),(2, '李四', 30, '销售部'),(3, '王五', 28, '财务部');2、向工资表中插入相应的数据:INSERT INTO SALARY (EMPID, SALARY)VALUES (1, 800000),(2, 1000000),(3, 600000);(四)数据的查询1、查询所有员工的信息:SELECT FROM EMPLOYEE;2、查询年龄大于 25 岁的员工信息:SELECT FROM EMPLOYEE WHERE AGE > 25;3、查询每个部门的平均工资:SELECT DEPARTMENT, AVG(SALARY) AS AVG_SALARY FROM EMPLOYEEJOIN SALARY ON EMPLOYEEEMPID = SALARYEMPID GROUP BY DEPARTMENT;(五)数据的更新1、将员工“张三”的年龄更新为 26 岁:UPDATE EMPLOYEESET AGE = 26WHERE NAME ='张三';(六)数据的删除1、删除员工表中“王五”的记录:DELETE FROM EMPLOYEEWHERE NAME ='王五';(七)索引的创建1、为员工表的“NAME”列创建索引:CREATE INDEX idx_employee_name ON EMPLOYEE (NAME);(八)存储过程的创建与使用1、创建一个存储过程,用于计算某个部门的总工资:CREATE PROCEDURE calculate_total_salary(IN department_name VARCHAR(50), OUT total_salary DECIMAL(10, 2))LANGUAGE SQLBEGINSELECT SUM(SALARY) INTO total_salaryFROM EMPLOYEEJOIN SALARY ON EMPLOYEEEMPID = SALARYEMPIDWHERE DEPARTMENT = department_name;END;2、调用存储过程计算“研发部”的总工资:CALL calculate_total_salary('研发部',@total_salary);SELECT @total_salary;四、实验结果及分析(一)实验结果1、数据库创建成功,能够正常连接和操作。
DB2 存储过程开发最佳实践COALESCE函数会依次检查输入的参数,返回第一个不是NULL的参数,只有当传入COALESCE函数的所有的参数都是NULL的时候,函数才会返回NULL。
例如, COALESCE(piName,''),如果变量piName为NULL,那么函数会返回'',否则就会返回piName本身的值。
下面的例子展示了如何对参数进行检查何初始化。
Person表用来存储个人的基本信息,其定义如下:表1: Person下面是用于向表Person插入数据的存储过程的参数预处理部分代码:表Person中num、name和age都是非空字段。
对于name字段,多个空格我们也认为是空值,所以在进行判断前我们调用RTRIM和COALESCE对其进行处理,然后使用 piName = '',对其进行非空判断;对于Rank 字段,我们希望如果用户输入的NULL,我们把它设置成"0",对其我们也使用COALESCE进行初始化;对于"Age"和"Num" 我们直接使用 IS NULL进行非空判断就可以了。
如果输入参数没有通过非空判断,我们就对输出参数poGenStatus设置一个确定的值(例子中为 34100)告知调用者:输入参数错误。
下面是对参数初始化规则的一个总结,供大家参考:1. 输入参数为字符类型,且允许为空的,可以使用COALESCE(inputParameter,'')把NULL转换成'';2. 输入类型为整型,且允许为空的,可以使用COALESCE(inputParameter,0),把空转换成0;3. 输入参数为字符类型,且是非空非空格的,可以使用COALESCE(inputParameter,'')把NULL转换成'',然后判断函数返回值是否为'';4. 输入类型为整型,且是非空的,不需要使用COALESCE函数,直接使用IS NULL进行非空判断。
最佳实践 3:正确设定游标的返回类型前面我们已经讨论了如何声明存储过程的返回结果集。
这里我们讨论一下结果集返回类型的问题。
结果集的返回类型有两种:调用者(CALLER) 和客户应用(CLIENT)。
首先我们看一下声明这两种游标的例子:代码中rs1游标的DECLAER语句中包含WITH RETURN TO CLIENT子句,表示结果集返回给客户应用(CLIEN T)。
rs2游标的DECLARE语句中包含WITH RETURN TO CALLER子句,表示结果集返回给调用者(CALLER)。
游标返回给调用者(CALLER)表示由存储过程的调用者接收结果集,而不考虑调用者是否是另一个存储过程,还是客户应用。
图(1)中存储过程PROZ如果声明为WITH RETURN TO CALLER,那么结果集会返回给存储过程PROY,Client Application是不会得到PROZ返回的结果集的。
图1:存储过程递归调用游标返回给客户应用(CLIENT)表示由发出最初 CALL 语句的客户应用接收结果集,即使结果集由嵌套层次中的 15 层深的嵌套存储过程发出也是如此。
图1中存储过程 PROZ 如果声明为 WITH RETURN TO CLIE NT,那么结果集会返回给 Client Application。
返回给客户应用(CLIENT)的游标声明是我们经常使用的,也是默认的结果集类型。
在声明返回类型时,我们要认真考虑一下,我们需要把结果集返回给谁,以免丢失返回集,导致程序错误。
最佳实践 4:异常(condition)处理在存储过程执行的过程中,经常因为数据或者其他问题产生异常(condition)。
根据业务逻辑,存储过程应该对异常进行相应处理或直接返回给调用者。
此处暂且将condition译为异常以方便读者理解。
实际上有些异常(condition)并非是由于错误引起的,下面将详细讲述。
当存储过程中的语句返回的SQLSTATE值超过00000的时候,就表明在存储过程中产生了一个异常(condi tion),它表示出现了错误、数据没有找到或者出现了警告。
为了响应和处理存储过程中出现的异常,我们必须在存储过程体中声明异常处理器(condition handler),它可以决定存储过程怎样响应一个或者多个已定义的异常或者预定义异常组。
声明条件处理器的语法如下,它会位于变量声明和游标声明之后:清单4:声明异常处理器异常处理器类型(handler-type)有以下几种:∙CONTINUE 在处理器操作完成之后,会继续执行产生这个异常语句之后的下一条语句。
∙EXIT 在处理器操作完成之后,存储过程会终止,并将控制返回给调用者。
∙UNDO 在处理器操作执行之前,DB2会回滚存储过程中执行的SQL操作。
在处理器操作完成之后,存储过程会终止,并将控制返回给调用者。
异常处理器可以处理基于特定SQLSTATE值的定制异常,或者处理预定义异常的类。
预定义的3种异常如下所示:∙NOT FOUND 标识导致SQLCODE值为+100或者SQLSATE值为02000的异常。
这个异常通常在SELE CT没有返回行的时候出现。
∙SQLEXCEPTIOIN 标识导致SQLCODE值为负的异常。
∙SQLWARNING 标识导致警告异常或者导致+100以外的SQLCODE正值的异常。
如果产生了NOT FOUND 或者SQLWARNING异常,并且没有为这个异常定义异常处理器,那么就会忽略这个异常,并且将控制流转向下一个语句。
如果产生了SQLEXCEPTION异常,并且没有为这个异常定义异常处理器,那么存储过程就会失败,并且会将控制流返回调用者。
以下示例声明了两个异常处理器。
EXIT处理器会在出现SQLEXCEPTION 或者SQLWARNING异常的时候被调用。
EXIT处理器会在终止SQL程序之前,将名为stmt的变量设为"ABORTED",并且将控制流返回给调用者。
UNDO处理器会将控制流返回给调用者之前,回滚存储过程体中已经完成的SQL操作。
清单5:异常处理器示例如果预定义异常集不能满足需求,就可以为特定的SQLSTATE值声明定制异常,然后再为这个定制异常声明处理器。
语法如下:清单6:定制异常处理器处理器可以由单独的存储过程语句定义,也可以使用由BEGIN…END块界定的复合语句定义。
注意在执行符合语句的时候,SQLSATE和SQLCODE的值会被改变,如果需要保留异常前的SQLSATE和SQLCODE,就需要在执行复合语句的第一个语句把SQLSATE和SQLCODE赋予本地变量或参数。
通常,我们会为存储过程定义一个执行状态的输出参数(例如:poGenStatus)。
根据这个输出状态,可以表明存储过程是否正确执行完毕。
我们需要定义一些异常处理器为这个输出参数赋值。
下面是一个例子:清单7:定义为输出参数赋值的异常处理器上面的异常处理器会在出现SQLEXCEPTION, SQLWARNING, NOT FOUND异常的时候触发。
异常处理器会取出当前的SQLCODE, SQLSTATE,然后根据它们的值来设置输出参数(poGenStatus)的值。
我们还可以定制一些异常处理器。
例如,我们可以定义一些对参数进行初始化的异常处理器。
这里,异常处理器可以看作是一个供存储过程自己调用的内部函数。
下面是这种情况的一个例子:清单8:供存储过程自己调用的内部函数上面定制的异常处理器负责对参数hSqlcode,hSqlstate和poGenStatus初始化。
当我们在程序中需要对它们初始化时,我们只需要调用SIGNAL sqlreset就可以了。
回页首最佳实践 5:合理使用临时表我们在储存过程开发中经常使用临时表。
合理的使用临时表可以简化程序的编写,提供执行效率,然而滥用临时表同样也会使得程序运行效率降低。
临时表一般在如下情况下使用:1. 临时表用于存储程序运行中的临时数据。
例如,如果在一个程序中第一条查询语句执行的结果会被后续的查询语句用到,那么我们可以把第一次查询的结果存储在一个临时表中供后续查询语句使用,而不是在后续查询语句中重新查询一次。
如果第一条查询语句非常复杂和耗时,那么上面的策略是非常有效的。
2. 临时表可以用于存储在一个程序中需要返回多次的结果集。
例如,程序中有一个很耗资源的多表查询,同时,该查询在程序中需要执行多次,那么就可以把第一次查询的结果集存储在临时保中,后续的查询只需要查临时表就可以了。
3. 临时表也可以用于让SQL访问非关系型数据库。
例如,可以编写程序把非关系型数据库中的数据插入到一个全局临时表中,那么我们就可以对其数据进行查询。
我们可使用 DECLARE GLOBAL TEMPORARY TABLE 语句来定义临时表。
DB2的临时表是基于会话的,且在会话之间是隔离的。
当会话结束时,临时表的数据被删除,临时表被隐式卸下。
对临时表的定义不会在SYSC AT.TABLES中出现下面是定义临时表的一个示例:清单9:定义临时表此语句创建一个名为 gbl_temp 的用户临时表。
定义此用户临时表所使用的列的名称和说明与 person 的列的名称和说明完全相同。
清单10:创建有两个字段的临时表此语句创建了一个有两个字段的临时表。
理论上临时表是不需要显示DROP的,因为它是基于会话的,当临时表基于的连接关闭的时候,临时表也就不存在了。
但是在实际开发中会有一些情况需要我们对临时表加以注意。
一种情况就是被调用的存储过程的返回值是一个基于临时表的结果集。
当存储过程执行完毕的时候,临时表并不会消失,因为返回的结果集相当于一个指针,指向临时表所在的内存地址,此时临时表是不会被DR OP掉的。
这种情况下,既不能在存储过程中删除这个临时表,也不应该由客户应用显示的删除临时表,这就容易出现一些问题。
下面我们通过一个例子来说明这个问题。
下面示例代码是返回临时表的存储过程(get_temp_table):清单11:返回临时表的存储过程存储过程中声明了有两个字段的临时表TEMP,声明了一个游标R_CRSR返回临时表中所有记录,最后在临时表中插入两条记录。
程序第一次执行的结果如下:图2:程序第一次执行的结果可以从图中看出,运行结果是我们期望的。
那么如果我们再运行一次,会有什么结果呢?下图是其运行结果:图3:程序再次执行的结果第二次执行的时候程序却出错了,这是因为在同一个连接中,临时表并没有被DROP掉,所以在第二次调用存储过程的时候就会出现临时表已经存在的错误。