670 likes | 940 Views
大型主机应用上的开放系统和中间件 2011 年度教育部 -IBM 精品课程. 同济大学软件学院 唐剑锋 billtangjf@gmail.com. 第 6 章 COBOL+CICS+VSAM 和 COBOL+CICS+DB2 程序开发. 6.1 COBOL+CICS 程序编写规范. 本章总结了一些 COBOL 内嵌 CICS 语言,也是我们编写 Online 程序的一些规范。 1. 程序开头说明: ***************************************************
E N D
大型主机应用上的开放系统和中间件2011年度教育部-IBM精品课程大型主机应用上的开放系统和中间件2011年度教育部-IBM精品课程 同济大学软件学院 唐剑锋 billtangjf@gmail.com
6.1 COBOL+CICS程序编写规范 • 本章总结了一些COBOL内嵌CICS语言,也是我们编写Online程序的一些规范。 • 1. 程序开头说明: *************************************************** * TONGJI MAINFRAME TESTING * * EMPLOYEE EXERCISE * * USAGE : BROWSE RECORDS IN EMPLOYEE FILE * * FILE USAGE : EMPLOYEE * * BMS USAGE : EMPMBR * *************************************************** • 首先我们必须在程序的起始部分注明一些必要的信息,要有程序所属的项目名、程序的解释、程序的用途、程序的使用说明(如果有的话)、程序所需要的文件(一般是VSAM文件)或数据库、程序所使用的BMS Map名。
2. 前两个DIVISIONS IDENTIFICATION DIVISION. PROGRAM-ID. EMPOBR. ENVIRONMENT DIVISION. IDENTIFICATION DIVISION中至少要申明PROGRAM-ID,它必须与我们这个程序的文件名是一致的。ENVIRONMENT DIVISION一般来说我们是不用指定的,因为所有的环境都是由CICS帮我们设定好的,不需要我们来定义。 • 3. DATA DIVISION部分 DATA DIVISION中主要包含三个部分: (1)WORKING-STORAGE SECTION • 在WORKING-STORAGE SECTION中设定所有要使用的变量。我们约定在所有的变量名之前都加上“WS-”(WS是WORKING-STORAGE的首字母)。在第一层我们建议写“01 WS-VARIABLE”,以后各层以05开始,每层加5。这样我们可以留出一定的层数以备不时之需,同时也使层次显得更为清晰。
WS中的前面部分,建议使用如下写法: 05 WS-INFO. 10 WS-TSQ-NAME. 15 WS-APPLID PIC X(2) VALUE 'TJ'. 15 WS-TRANID PIC X(4) VALUE 'FX01'. 15 WS-PROGSUF PIC X(3) VALUE '001'. 15 WS-SEQ PIC X(3) VALUE '001'. 15 WS-TERMID PIC X(4) VALUE SPACES. 10 DSTX-ID PIC X(4) VALUE 'FX01'. 88 DSTX-ID-VALID VALUE 'FX01'. 10 WS-TSQ-CONTENT. 15 WS-TSQ-LEVEL PIC 9(4). 15 WS-TSQ-TRANID PIC X(4) VALUE SPACES. 10 WS-TSQ-CURR-ITEM PIC S9(4) COMP. 10 WS-LEVEL PIC 9(4) VALUE 0.
TSQ-NAME分为项目名(APPLID)、交易名(TRANID)、程序后缀(PROGSUF)、序列号(SEQ)、终端号(TERMID)。这样可以确保程序所使用的TSQ是唯一的,不会与其他人冲突。TSQ-NAME分为项目名(APPLID)、交易名(TRANID)、程序后缀(PROGSUF)、序列号(SEQ)、终端号(TERMID)。这样可以确保程序所使用的TSQ是唯一的,不会与其他人冲突。 • DSTX-ID标示了该程序的TRANSID,用于比较TSQ中的TRANSID,抽出来便于修改。 • WS-TSQ-CONTENT表示了TSQ中所要保存的内容,在里面至少应包括两个部分:WS-TSQ-LEVEL和WS-TSQ-TRANID。前者表示我们希望下次任务所处的层数或上次任务希望这次所在的层数。然后,希望在TSQ中存什么信息就加在该层后面,比如想要保存的Map中域的值。 • WS-TSQ-CURR-ITEM在TSQ中要用到,一般都会设定其为1。 • WS-LEVEL指定现在这个任务所处的层。
(2)COPY 部分 COPY EMPMBR. COPY EMPLOYEE REPLACING ==EMPLOYEE:== BY ==EMPLOYEE-==. • 可以使用COPY命令将需要的其他文件中的COPYBOOK给拷贝过来。一般来说,如果是BMS Map的COPYBOOK,则直接拷贝进来即可。如果是VSAM文件的定义,拷贝进来之后,一般都要用REPLACING来将原本“:”改为“-”。这是一种规范,在我们写VSAM文件的定义时,一般要在变量名之前加上文件名和“:”,这样便于将文件前缀与变量名区别开来。
(3)LINKAGE SECTION 01 DFHCOMMAREA PIC X(200). • 如果这个程序是要被调用的,那么在LINKAGE SECTION中是必须指定的。这与LINK或XCTL中COMMAREA的参数相关。如果这个程序不需要被调用,则不需指定。
4. PROCEDURE DIVISION部分 • 首先要先明确一些层的作用和规范。 • 我们约定000-MAIN作为程序的开始段,Z000-RETURN作为程序的结束段。除了000-MAIN 和 Z000-RETURN之外,其他的代码段都要有一个对应的EXIT。 例如:A100-GETLV. …… A100-EXIT. EXIT. • 特别提示:程序是看XXXX-EXIT来结束这个代码段的。A100-GETLV是一个标签(所有从A区开始的,我们叫做标签LABEL),程序会从一个标签执行到另一个标签。虽然我们可以不写A100-EXIT而仅靠下一个标签结束,但是为了程序的规范性,建议以A100-EXIT来与A100-GETLV对应,同时加上EXIT作为A100-EXIT的DUMMY语句,这样可以把A100-EXIT这个标签与下一个标签区分开来(如果不写EXIT,程序会报错)。
000-MAIN. 所有程序的开始。 • 第一句必须是EXEC CICS HANDLE ABEND LABEL(Z000-RETURN) END-EXEC. • 这将接受后面所有产生的无其他异常处理的错误。此后应尽量避免使用 HANDLE 语句进行出错处理,而是根据可能出现的错误情况分别处理,例如使用DFHRESP判断CICS语句执行的错误。 • 然后进行程序变量的初始化:PERFORM 010-PROG-INIT THRU 010-EXIT. • 得到该次的层数:PERFORM A100-GETLV THRU A100-EXIT. • 得到LEVEL之后我们就可以通过不同层次来处理具体的操作: IF WS-LEVEL = 0 …… ELSE IF WS-LEVEL = 1 …… ELSE PERFORM Z000-RETURN END-IF.
010-PROG-INIT. MOVE EIBTRMID TO WS-TERMID. • 初始化TSQ-NAME,补充完整TSQ-NAME,正是这句能保证每个TSQ的唯一性。 PERFORM B101-INIT-MAP THRU B101-EXIT. • 初始化Map,能够保证Map的初始值是正确的。 PERFORM B102-INIT-ATTR THRU B102-EXIT. • 初始化Map域的属性,能够保证Map的域的属性是正确的。 • A层用于最基本的TSQ的处理代码段。 A100-GETLV. • 从READQ开始, 从TSQ中得到WS-TSQ-LEVEL的信息,然后通过MOVE语句送给WS-LEVEL,从而得到当前层的信息.
A200-SETLV. • 设置LEVEL。在伪对话程序中,为了在程序两次执行中保留必要的状态等数据信息,需要将WS-TSQ-CONTENT中的内容,包括WS-TSQ-LEVEL和WS-TSQ-TRANID写入TSQ,使用WRITEQ或者加REWRITE选项(这将根据所处的层数或一些特殊的条件来决定)。第一次必须是WRITEQ,以后都将加REWRITE属性。 A300-CLEARQ. • 清除TSQ。一般都是在程序都结束之前使用,使用DELETEQ。同时建议在DELETEQ之前先将Map的所有域清空一下,用PERFORM B101-INIT-MAP THRU B101-EXIT将该内存空间初始化。
B层用于MAP的处理代码段。 B100-SEND-MAP. • 用于SEND MAP的代码段。由于SEND MAP就表示这次任务结束了,所以,建议在SEND MAP之前使用SETLV,也就是做WRITEQ的工作。 B101-INIT-MAP. • 一般一张MAP都要配备两个代码段,分别是初始化Map和初始化Map域的属性。B101-INIT-MAP代码段用于将所有字符型的域赋值SPACES,数字型的域赋值0。 B102-INIT-ATTR. • 该代码段将所有域的属性清空,将所有的域名以A结尾的变量都赋值为LOW-VALUE,这样可以保证每次得到的Map域的属性都是正确的。 B200-RECEIVE-MAP. • 用于RECEIVE MAP 的代码段。在RECEIVE MAP之前,一般会有如下代码: EXEC CICS HANDLE AID CLEAR (Z000-RETURN) PF3 (Z000-RETURN) ENTER (C100-BROWSE) ANYKEY (C100-BROWSE) END-EXEC.
一般来讲按F3键表示退出(有些是回到上一张MAP,有些是直接回到CICS),其他功能键都建议使用习惯用法。一般来讲按F3键表示退出(有些是回到上一张MAP,有些是直接回到CICS),其他功能键都建议使用习惯用法。 • 建议上述代码中包含ANYKEY,表示在键盘上按下除了清屏键、F3键和回车键以外的其他键所执行的动作,否则如果使用没有设定过的键就会退出任务,这往往不是我们所希望的。
如果程序中有不止一张的MAP,分别需要处理程序段,其命名规则一般遵循以下原则:如果程序中有不止一张的MAP,分别需要处理程序段,其命名规则一般遵循以下原则: B1@0-SEND-MAP B1@1-INIT-MAP B1@2-INIT-ATTR B2@0-RECEIVE-MAP • 其中@表示从1到9的数字或者从A到Z的字母,表示是第几张MAP(9之后为A,本命名规则最多可以包含35张MAP)。 • 比如,第一张MAP的一些代码段就是: B110-SEND-MAP. B111-INIT-MAP. B112-INIT-ATTR. B210-RECEIVE-MAP. • 即B层的后3位分别表示:第一个,1为SEND,2为RECEIVE;第二个,表示为第几张MAP;第三个0表示SEND或RECEIVE,1以后的表示辅助的代码段,如SEND的1为INIT-MAP,2为INIT-ATTR。
C层用于具体的代码段的处理。包括没有VSAM和DB2参与的COBOL+CICS的代码段的处理,有VSAM参与的COBOL+CICS+VSAM的代码段的处理,有DB2参与的COBOL+CICS+DB2的代码段的处理。C层用于具体的代码段的处理。包括没有VSAM和DB2参与的COBOL+CICS的代码段的处理,有VSAM参与的COBOL+CICS+VSAM的代码段的处理,有DB2参与的COBOL+CICS+DB2的代码段的处理。 • 对于COBOL+CICS+VSAM的例子来说,读取VSAM数据及后续处理的核心样例代码如下: MOVE MYNAMEI(1:6) TO WS-STDNUM EXEC CICS READ FILE('K211T01') RIDFLD(WS-STDNUM) INTO(C0S11T01-REC) RESP(WS-FILE-RESP) END-EXEC IF WS-FILE-RESP = DFHRESP(NORMAL) MOVE C0S11T01-NAME TO MYMSGO ELSE MOVE 'RECORD NOT FOUND' TO MYMSGO END-IF • 该代码片断实现的功能是:用EXEC CICS READ FILE命令,按VSAM的关键字WS-STDNUM查询出非关键字C0S11T01-NAME的值,并将其传送给COPYBOOK中的输出变量MYMSGO,以便通过SEND MAP送出到屏幕显示给用户。
对于COBOL+CICS+DB2的例子来说,读取DB2数据及后续处理的核心样例代码如下:对于COBOL+CICS+DB2的例子来说,读取DB2数据及后续处理的核心样例代码如下: MOVE MKEYI(1:6) TO BOOKNO EXEC SQL SELECT BOOKNAME INTO :BOOKNAME FROM TJD0211.TT01C01 WHERE BOOKNO = :BOOKNO END-EXEC IF SQLCODE = 0 MOVE BOOKNAME TO MCONTENO ELSE MOVE '**FETCH ERROR**' TO MCONTENO END-IF • 该代码片断实现的功能跟上面 COBOL+CICS+VSAM的例子的功能差不多:用EXEC SQL SELECT语句,按DB2的主键BOOKNO查询出非主键BOOKNAME的值,并将其传送给COPYBOOK中的输出变量MCONTENO,以便通过SEND MAP送出到屏幕显示给用户。
Z000-RETURN. • 表示所有程序的结束,样例代码如下: MOVE 0 TO WS-TSQ-LEVEL. MOVE SPACES TO WS-TSQ-TRANID. PERFORM A300-CLEARQ THRU A300-EXIT. EXEC CICS SEND CONTROL ERASE END-EXEC EXEC CICS RETURN END-EXEC GOBACK. EXIT. 这个是比较定式,当然也可以根据需要来自行的加一些动作。 • 5. 其他 • 除了以上的部分外,还要注意一点:在所有代码段的第一层,必须加“.”,在第一层以下的都不要加,否则会导致程序逻辑出错,或语法错误。
6.2 COBOL+CICS样例程序开发 • 本节在6.1节的基础上,论述COBOL+CICS样例程序的开发过程。 • COBOL+CICS样例程序的MAP源代码如下面三页所示:
注意COBOL+CICS样例程序的MAP源代码和COPY BOOK不需要用户手工编写,而是由主机端的SDFII工具自动生成。因生成过程比较繁杂,在此略。有兴趣的同学可参考相关文档。
编译、链接上述COBOL+CICS样例程序的MAP源代码的JCL如下:编译、链接上述COBOL+CICS样例程序的MAP源代码的JCL如下:
上述JCL要调用到的过程DFHLNKV1代码如下: • 提交上述JCL并成功(MAXCC<=4)后,便在STRB.CICS.LOAD中生成一个MAPSET M211T01。 • 自此,COBOL+CICS样例程序的CICS MAP代码生成并执行完毕。
COBOL+CICS程序样例源代码如下面八页所示,其中程序的基本逻辑在6.1 程序编写规范已经基本论述完毕。
CICS翻译、COBOL编译、链接上面的COBOL+CICS源程序的JCL如下面三页所示:CICS翻译、COBOL编译、链接上面的COBOL+CICS源程序的JCL如下面三页所示:
提交上述JCL并成功(MAXCC<=4)后,便在STRB.CICS.LOAD中生成一个PROGRAM C0O11T1。 • 自此,COBOL+CICS样例程序的源代码编写并执行完毕。
下面在CICS Region里创建各个资源,这些资源包括MAPSET,PROGRAM和TRANSACTION。 • 在CICS Region里输入如下命令创建MAPSET: CEDA DEF MAPSET(M211T01) G(TJD0211) • 在CICS Region里输入如下命令创建PROGRAM: CEDA DEF PROG(C0O11T1) G(TJD0211) • 在CICS Region里输入如下命令创建TRANSACTION: CEDA DEF TRANSACTION(A211) PROG(C0O11T1) G(TJD0211) • 在CICS Region里输入如下命令安装定义的上述资源: CEDA INS G(TJD0211) • 自此,COBOL+CICS样例程序的CICS资源都已经定义并安装完毕。
下面执行刚刚创建并安装好的交易。在CICS Region里输入A211,回车,如果一切正常,将出现如下屏幕: • 在ENTER YOUR ID HERE:处随意输入一个用户名,如TANGJF,按回车,MESSAGE:处将显示:HELLO,TANGJF!。
6.3 COBOL+CICS+VSAM样例程序开发 • 本节在6.1节的基础上,论述COBOL+CICS+VSAM样例程序的开发过程。 • 创建本节中用到的VSAM数据集的JCL如下:
VSAM数据集定义好以后,下一步是向VSAM数据集TJD0211.L11.C0K11T01中插入样本数据,我们用DITTO工具来完成这一工作。方法如下:VSAM数据集定义好以后,下一步是向VSAM数据集TJD0211.L11.C0K11T01中插入样本数据,我们用DITTO工具来完成这一工作。方法如下: • 在ISPF主菜单中输入M.7,进入DITTO界面。按如下界面输入信息: • 按回车后得到如下界面,在Data set name处输入要插入数据的VSAM数据集的名字,用单引号括起来,如下所示:
按回车后,出现空的VSAM数据集,向VSAM数据集插入如下内容(操作同在普通PDS数据集的Member或PS数据集中插入数据的方法相同,此处略):按回车后,出现空的VSAM数据集,向VSAM数据集插入如下内容(操作同在普通PDS数据集的Member或PS数据集中插入数据的方法相同,此处略): • 自此,本节中要用到的VSAM数据集创建完毕并插入数据。
COBOL+CICS+VSAM样例程序的MAP源代码和COPY BOOK与COBOL+CICS样例程序的MAP源代码和COPY BOOK几乎相同,限于篇幅,此处略去。相应的编译、链接上述COBOL+CICS+VSAM样例程序的MAP源代码的JCL也略去。 • 提交上述JCL并成功(MAXCC<=4)后,便在STRB.CICS.LOAD中生成一个MAPSET M211T02。 • 自此,COBOL+CICS+VSAM样例程序的CICS MAP生成并执行完毕。
然后开始编写COBOL+CICS+VSAM样例程序的源代码。COBOL+CICS+VSAM与COBOL+CICS源程序的主逻辑非常相似,受篇幅限制,此处只介绍加入VSAM的处理逻辑后与COBOL+CICS的程序不同之处的代码。然后开始编写COBOL+CICS+VSAM样例程序的源代码。COBOL+CICS+VSAM与COBOL+CICS源程序的主逻辑非常相似,受篇幅限制,此处只介绍加入VSAM的处理逻辑后与COBOL+CICS的程序不同之处的代码。 (1)首先在程序一开始的注释中加入如下代码: • 上述注释表示应用程序中将用到VSAM文件C0K11T01,并且VSAM对应的COPYBOOK是C0S11T01。 (2)在第二个01 WS-VARIABLE.中加入如下代码: • 上述WS-STDNUM作为VSAM的Key送入READ FILE命令的RIDFLD,当CICS反馈信息为正常时,将得到VSAM的其他Non Key的数据。
(3)在引入COPYBOOK的代码COPY C0M11T2. 后面加入如下代码: • 上述COPY语句在上文6.1中的(2)COPY 部分已经解释完毕,故此处略。 (4)在A300-PROCESS程序段书写如下代码: 该代码片断实现的功能在上文6.1中的4.PROCEDURE DIVISION部分已经解释完毕,故此处略。
CICS翻译、COBOL编译、链接上面的COBOL+CICS+VSAM源程序的JCL与CICS翻译、COBOL编译、链接上面的COBOL+CICS源程序的JCL非常类似,只需要将所有含C0O11T1的地方(共计两处)替换成C0O11T2,提交即可,故在此省略JCL代码。CICS翻译、COBOL编译、链接上面的COBOL+CICS+VSAM源程序的JCL与CICS翻译、COBOL编译、链接上面的COBOL+CICS源程序的JCL非常类似,只需要将所有含C0O11T1的地方(共计两处)替换成C0O11T2,提交即可,故在此省略JCL代码。 • 提交上述JCL并成功(MAXCC<=4)后,便在STRB.CICS.LOAD中生成一个PROGRAM C0O11T2。 • 自此,COBOL+CICS+VSAM样例程序的源代码编写并执行完毕。
下面在CICS Region里创建各个资源,这些资源包括FILE,MAPSET,PROGRAM和TRANSACTION。 • 在CICS Region里输入如下命令创建VSAM FILE的定义: CEDA DEF FILE(K211T01) G(TJD0211) • 运行以上命令后,还需要进到K211T01中进行如下设置(部分)。其中粗体项表示必填参数。
如果VSAM数据集没有打开,还需要在CICS Region里运行如下命令将K211T01打开: CEMT I FILE(K211T01) • 结果如下: • 将Clo替换成Ope,回车,将VSAM数据集K211T01打开。 • 在CICS Region里输入如下命令创建MAPSET: CEDA DEF MAPSET(M211T02) G(TJD0211) • 在CICS Region里输入如下命令创建PROGRAM: CEDA DEF PROG(C0O11T2) G(TJD0211) • 在CICS Region里输入如下命令创建TRANSACTION: CEDA DEF TRANSACTION(B211) PROG(C0O11T2) G(TJD0211) • 在CICS Region里输入如下命令安装定义的上述资源: CEDA INS G(TJD0211) • 自此,COBOL+CICS+VSAM样例程序的CICS资源都已经定义并安装完毕。
下面执行刚刚创建并安装好的交易。在CICS Region里输入B211,回车,如果一切正常,将出现如下屏幕: • 在ENTER YOUR ID HERE:处输入VSAM数据集中具有的一个KEY值。如000001,按回车,MESSAGE:处将显示:HELLO, VSAMDATA1 !其中VSAMDATA1是KEY 000001对应的NON KEY的值。