大型机CICS中的分页逻辑

use*_*461 1 db2 cobol mainframe cics

这是我的要求.

Front(客户端)端将根据预定义条件进行搜索(例如:客户ID,帐号,名字,姓氏等).我需要从db2数据库获取与此请求相对应的数据并将其发送回它们(服务器).我们使用CICS通道和容器在客户端和服务器之间传递请求和响应.

前端需要按以下顺序排列的数据:接收日期降序,客户ID升序,帐号升序.数据以500条记录的页面提取.例如,如果来自前端的搜索请求将从db2数据库中检索50,000条记录,则我们需要在500条记录"页面"中返回此数据.对于分页概念,我们使用字段安全存款号,它是我们数据库的主键,但排序顺序不是基于此字段.

我想知道我们是否可以在CICS中使用可滚动游标逻辑来实现分页.

请注意,我不喜欢使用内部阵列冒泡排序来响应发送数据,因为它会降低性能.我喜欢通过查询逻辑来做.有什么想法吗?

示例(初始前端输入请求):

  • 客户ID:A
  • 第一次请求(以确定它是第一次或下次或先前的分页请求)
  • 第一保证金号码:0
  • 上次保证金编号:0

由于这是第一次请求,这个字段从前端都是零,我们需要根据保证金条件> 0从数据库中检索记录

Db2数据库:

  • 该标准有700条记录
  • 第一次主机响应:我们将发送前500条记录

然后前端将发送获取下一组记录的请求,其中包含:

  • 客户ID:A
  • 下一个请求
  • 第一笔保证金金额:0
  • 上次保证金号码:17980

因此,对于此详细信息,如果我根据安全存款编号> 17980查询我的数据库,则可能会再次在屏幕中列出重复记录,因为我们的数据库中的排序顺序不是基于安全存款编号

如何阻止这种逻辑?

Nea*_*alB 6

IBM Mainframe环境中的许多客户端/服务器应用程序涉及伪对话CICS事务.如果您在psueudo对话模式下使用CICS,则服务器无法在返回到客户端时保留cusors.因此,可滚动的cusors在这种环境中几乎没有用处.所以回答你的基本问题:这里不能使用可滚动游标.

这里的"技巧"是在服务器中创建可重新启动的SQL谓词.然后,它将从任何给定的说明点以正确的顺序拾取行.当客户端调用您的服务器时,它必须将所有定位信息传递给您的服务器.

通常,在客户端的第一次调用中,所有定位值都被设置为使光标从必须是第一行的位置开始定位.然后,服务器提取一个"页面"值的数据并将其返回给客户端.在下一页转发请求中,客户端将这些定位值设置为它显示的最后一行,并调用服务器以获取下一个"页面"数据.

在您的情况下,我会假设页面前进光标看起来像这样,所有带有RESTART前缀的变量...是客户端必须提供给服务器以将光标启动到正确位置的内容.

 DECLARE CURSOR Page-forward FOR
    SELECT Receive_Date, Customer_id, Account_Nbr, Security_Dep_Id
    FROM Table_Name
    WHERE (   (Receive_Date    < :RESTART-RCV-DT)
           OR (Receive_Date    = :RESTART-RCV-DT AND
               Customer_Id     > :RESTART-CUSTOMER-ID)
           OR (Receive_Date    = :RESTART-RCV-DT AND
               Customer_Id     = :RESTART-CUSTOMER-ID AND
               Account_Nbr     > :RESTART-ACCT-NBR)
           OR (Receive_Date    = :RESTART-RCV-DT AND
               Customer_Id     = :RESTART-CUSTOMER-ID AND
               Account_Nbr     = :RESTART-ACCT-NBR AND
               Security_Dep_Id > :RESTART-SEC-DEP-ID))
    ORDER BY 1 DESC, 2 ASC , 3 ASC, 4 ASC
Run Code Online (Sandbox Code Playgroud)

对于初始调用,客户端将传递类似'9999-12-31'的内容作为RESTART-RCV-DT,对于RESTART-CUSTOMER-ID,RESTART-ACCT-NBR和SEC-DEP-ID为零(假设这些是所有数字).如果仔细查看游标谓词,可以验证在这些值之前不能有任何行 - 因此这将返回第一页数据.如果客户端需要在此之后向前翻页,它必须告诉服务器从收到的最后一行之后的下一行开始.为此,它将使用刚刚显示的页面上最后一行的值填充RESTART ...变量.此过程将驱动光标一次向前选择一页.

在进行分页时,过程是相反的(您需要第二个光标来支持此过程,并且客户端需要告诉您页面的哪个方向:前进或后退).客户端需要使用从服务器收到的第一行填充RESTART变量.服务器在页面请求上的技巧是以相反的顺序将数据返回给客户端.您可能必须以相反的顺序填充传回客户端的数据页(即将检索到的第一行放入客户端和服务器之间共享的分页区的最后一行).页面向后光标看起来像:

 DECLARE CURSOR Page-backward FOR
    SELECT Receive_Date, Customer_id, Account_Nbr, Security_Dep_Id
    FROM Table_Name
    WHERE (   (Receive_Date    > :RESTART-RCV-DT)
           OR (Receive_Date    = :RESTART-RCV-DT AND
               Customer_Id     < :RESTART-CUSTOMER-ID)
           OR (Receive_Date    = :RESTART-RCV-DT AND
               Customer_Id     = :RESTART-CUSTOMER-ID AND
               Account_Nbr     < :RESTART-ACCT-NBR)
           OR (Receive_Date    = :RESTART-RCV-DT AND
               Customer_Id     = :RESTART-CUSTOMER-ID AND
               Account_Nbr     = :RESTART-ACCT-NBR AND
               Security_Dep_Id < :RESTART-SEC-DEP-ID))
    ORDER BY 1 ASC, 2 DESC , 3 DESC, 4 DESC
Run Code Online (Sandbox Code Playgroud)

正如在其他答案中已经指出的那样,这种类型的分页过程不管理或检测可能在寻呼事务中发生的对数据库的并发更新.这是另一天的另一个话题......

开发可重新启动的游标

构建分页服务器的关键是开发一个可从客户端事务接收的一组值重新启动的游标.这样就可以控制客户端的光标定位和方向.这也意味着客户必须从服务器接收所有关键定位数据,即使客户可能实际上并未将这些数据用于任何其他目的(例如,从您的问题我得到的印象是客户可能不需要保证金ID,除非提供作为您的服务器的定位参数)

要构建分页服务器,您需要知道所需的数据排序顺序是什么(例如,接收日期降序,然后是客户ID升序,然后是帐号升序).您还需要知道唯一标识游标返回的行的数据集.在您的情况下,这将是安全存款ID(这是您选择的表的主键,因此它对于该表中的每一行必须是唯一的).知道了这一点,然后构建一个游标谓词(WHERE子句中的东西),它将以所需的排序顺序返回客户端所需的数据,该顺序还包括完整的定位键(即安全存款ID).如果最终定位键被消除,则两个或更多个返回的行可以包含相同的数据,这使得定位键被包括作为排序条件是重要的.它是升序还是降序并不重要,但需要将其包含在排序中以确保数据检索的一致顺序.

可以遵循一个相当简单的公式来为支持分页服务器所需的可重新启动的cusor构建谓词.基本上这是一系列"OR"子句,它们连接一系列"AND"子句,这些子句按照客户端要求的排序顺序逐渐变得更具选择性并最终得到定位键.

要了解其工作原理,请考虑如何开发服务器的查询...

从最不经常更改的排序顺序开始...

SELECT ... 
FROM ... 
WHERE Receive_Date < restart value
Run Code Online (Sandbox Code Playgroud)

这将在指定的重新启动接收日期之前检索所有行,而不管其他列重启值是什么(例如,只要接收日期小于任何接收日期,客户ID的范围可以从最小值到最大值"到目前为止" ).由于此列仅在排除了所有子排序列值后才更改值,因此您可以确保在完全重新启动键之前不会拾取任何行.但是那些与重启请求在同一天发生但具有更大客户ID的行呢?这些可以用....

SELECT ... 
FROM ... 
WHERE Receive_Date = restart value AND
      Customer_id > restart value
Run Code Online (Sandbox Code Playgroud)

那些接收日期和客户ID与重新启动密钥相同但帐号较大的那些?这些可以用......

SELECT ... 
FROM ... 
WHERE Receive_Date = restart value AND
      Customer_Id = restart value AND
      Account_Nbr > restart value
Run Code Online (Sandbox Code Playgroud)

继续此模式,直到处理完全重启键.请注意,不等号是由排序顺序决定的.使用<时,列进行排序和降序>上升时.另请注意,每个查询的SELECTFROM子句完全相同 - 这意味着您可以使用OR结合将它们全部放在一起...

SELECT Receive_Date, Customer_id, Account_Nbr, Security_Dep_Id
FROM Table_Name
WHERE (   (Receive_Date    < :RESTART-RCV-DT)
       OR (Receive_Date    = :RESTART-RCV-DT AND
           Customer_Id     > :RESTART-CUSTOMER-ID)
       OR (Receive_Date    = :RESTART-RCV-DT AND
           Customer_Id     = :RESTART-CUSTOMER-ID AND
           Account_Nbr     > :RESTART-ACCT-NBR)
       OR (Receive_Date    = :RESTART-RCV-DT AND
           Customer_Id     = :RESTART-CUSTOMER-ID AND
           Account_Nbr     = :RESTART-ACCT-NBR AND
           Security_Dep_Id > :RESTART-SEC-DEP-ID))
ORDER BY 1 DESC, 2 ASC , 3 ASC, 4 ASC
Run Code Online (Sandbox Code Playgroud)

你去...一个可重启的游标,用于前向寻呼.用于向后分页的游标的构造遵循类似的模式,只需翻转排序顺序并重复.