【问题标题】:Pagination logic in Mainframe CICS大型机 CICS 中的分页逻辑
【发布时间】:2014-03-15 13:08:41
【问题描述】:

这是我的要求。

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

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

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

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

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

  • 客户编号:A
  • 第一次请求(确定是第一次还是下一次或上一次请求分页)
  • 首个保证金号码:0
  • 最后保证金号码:0

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

Db2 数据库:

  • 此条件有 700 条记录
  • 大型机首次响应: 我们将发送前 500 条记录

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

  • 客户编号:A
  • 下一个请求
  • 第一笔保证金号码:0
  • 最后保证金号码:17980

所以对于这个细节,如果我根据保证金号码> 17980查询我的数据库,它可能会导致屏幕上再次列出重复的记录,因为我们在数据库中的排序顺序不是基于保证金号码

如何实现这个逻辑??

【问题讨论】:

  • Bill woodger:您对 db2 中的可滚动光标有任何想法吗?我们有 db2 版本 10。

标签: db2 cobol mainframe cics


【解决方案1】:

IBM 大型机环境中的许多客户端/服务器应用程序都涉及伪会话 CICS 事务。 如果您在伪会话模式下使用 CICS 当服务器返回给客户端时,服务器不可能持有游标。因此可滚动的游标 在这种环境下用处不大。因此,回答您的基本问题:此处不能使用任何可滚动光标。

这里的“技巧”是在服务器中创建一个可重新启动的 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

对于初始调用,客户端将传递类似“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

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

开发可重启游标

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

构建分页服务器你需要知道 数据所需的排序顺序是什么(例如,接收日期降序,然后客户 ID 升序 帐号升序)。 您还需要知道唯一标识一行的数据集 由光标返回。在您的情况下,这将是保证金 ID(这是 您从中选择的表,因此该表中的每一行都必须是唯一的)。知道了这一点,你就可以建立一个 游标谓词(WHERE 子句中的内容)将按所需的排序顺序返回客户端所需的数据 还包括 完整的定位密钥(即保证金 ID)。如果两个或更多返回的行可能包含相同的数据,如果 最终的定位键被消除,因此将定位键作为排序条件包含在内很重要。 不管是升序还是降序,都需要包含在排序中,以确保一致 数据检索顺序。

可以遵循一个相当简单的公式来为可重新启动的游标构建谓词 支持分页服务器。基本上,这是连接一系列“AND”子句的“OR”子句的级联 按照客户要求的排序顺序逐渐变得更有选择性并最终定位 键。

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

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

SELECT ... 
FROM ... 
WHERE Receive_Date < restart value

这将检索指定重新开始接收日期之前的所有行,而不管其他 列重新启动值是(例如,客户 ID 的范围可以从最小值到最大值,只要接收日期 小于迄今为止“看到”的任何接收日期)。由于此列仅在所有从属排序列值之后更改值 已经用尽你可以确定这不会在完全重启键之前拾取任何行。 但是那些与重新启动请求在同一日期发生但具有 更大的客户 ID?这些可以用...捡起。

SELECT ... 
FROM ... 
WHERE Receive_Date = restart value AND
      Customer_id > restart value

接收日期和客户 ID 与重启键相同但具有 更大的帐号?这些可以通过...获取。

SELECT ... 
FROM ... 
WHERE Receive_Date = restart value AND
      Customer_Id = restart value AND
      Account_Nbr > restart value

继续此模式,直到处理完完整的重新启动密钥。注意不等式 符号由排序顺序决定。当列按降序排序时使用&lt;,当按升序排序时使用&gt;。 还要注意 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

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

【讨论】:

    【解决方案2】:

    一种简单的方法:编写 SQL 以按照您指定的排序顺序根据您的条件检索数据。然后只检索键到你想要的行。将密钥保存在您在后续调用事务时可以访问的地方。查看 DB2 中的多行选择。还了解 CICS 中的伪对话编程技术。

    现在我们开始讨论 Bill Woodger 提到的设计含义,您没有在问题中具体说明,这就是我刚刚达到简单方法的高点的原因。

    如果您的结果集在一次调用和下一次调用之间发生更改,您的结果将不会反映这些更改。您必须决定这是否重要。

    您提到了“前端”,但没有具体说明它是什么。如果它是 BMS 应用程序,您可以将密钥保存在您的 commarea 或容器中。如果您的前端是一个分布式应用程序,通过 CICS Web 服务或 CICS Web 支持或 MQ 或原始套接字或其他方式调用您的事务,您必须设计一种机制来存储这些密钥,以便您可以唯一地检索它们——也许通过发送一个人为的密钥返回到它必须在后续调用时提供的分布式应用程序。那么你必须有一些过程来清理你的密钥库。

    为您的问题创建一个在您的 IT 商店中独一无二的解决方案并不是孤立地完成的事情。您必须让负责维护您的应用程序的其他人参与进来,您的项目外部可能有一个小组负责做出此类决定,您的解决方案可能存在基础架构问题。

    因此,这与其说是对您的问题的回答,不如说是对您可能得不到答案的详细说明,或者至少是您似乎想要的答案。

    【讨论】:

      猜你喜欢
      • 2021-05-21
      • 1970-01-01
      • 2021-09-27
      • 2018-02-16
      • 1970-01-01
      • 2016-03-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-07
      相关资源
      最近更新 更多