对于最新稳定版本,请使用Spring Batch Documentation 6.0.0spring-doc.cadn.net.cn

批量处理与事务

简单批处理无重试

请考虑以下一个没有重试的嵌套批次示例。它显示了一个 批处理的常见场景:输入源被处理直到耗尽,且 它会在处理“块”结束时定期提交。spring-doc.cadn.net.cn

1   |  REPEAT(until=exhausted) {
|
2   |    TX {
3   |      REPEAT(size=5) {
3.1 |        input;
3.2 |        output;
|      }
|    }
|
|  }

输入作(3.1)可以是基于消息的接收(如来自JMS)或 基于文件的读取,但为了恢复并继续处理,有机会完成 整个工作,必须是交易性的。3.2版本的作也是如此。必须如此 要么是交易型,要么是幂零型。spring-doc.cadn.net.cn

如果块在重复(3) 由于数据库异常在3.2时失败,则德州(2) 必须回滚整个数据块。spring-doc.cadn.net.cn

简单无状态重试

对于非事务作使用重试也很有用,例如 调用Web服务或其他远程资源,如下示例所示:spring-doc.cadn.net.cn

0   |  TX {
1   |    input;
1.1 |    output;
2   |    RETRY {
2.1 |      remote access;
|    }
|  }

这实际上是重试最有用的应用之一,因为远程调用是 比数据库更新更可能失败且可重试。只要遥控器 访问(2.1)最终成功,交易,德州(0),提交。如果遥控器 访问(2.1)最终失败,交易,德州(0),保证掷骰 返回。spring-doc.cadn.net.cn

典型的重复-重试模式

最常见的批处理模式是向 块,如下例子所示:spring-doc.cadn.net.cn

1   |  REPEAT(until=exhausted, exception=not critical) {
|
2   |    TX {
3   |      REPEAT(size=5) {
|
4   |        RETRY(stateful, exception=deadlock loser) {
4.1 |          input;
5   |        } PROCESS {
5.1 |          output;
6   |        } SKIP and RECOVER {
|          notify;
|        }
|
|      }
|    }
|
|  }

内层重试(4) 块标记为“有状态”。请参见有状态重试的典型用例描述。这意味着,如果 重试过程(5) 阻挡失败,以及重试(4) 如下:spring-doc.cadn.net.cn

  1. 抛出异常,回滚交易,德州(2),在块级, 允许该项重新呈现到输入队列。spring-doc.cadn.net.cn

  2. 当该项目重新出现时,可能会根据现有的重试策略进行重试,且 执行过程(5)再来一次。第二次及之后的尝试可能会再次失败, 重新抛出例外。spring-doc.cadn.net.cn

  3. 最终,该物品最后一次出现。重试政策不允许再尝试一次 尝试,所以过程(5)从未被执行。在这种情况下,我们遵循恢复(6) 路径,实际上是“跳过”已接收并正在处理的项目。spring-doc.cadn.net.cn

注意所用的符号重试(4) 在计划中明确显示 输入步骤(4.1)是重试的一部分。同时也明确指出有两个 处理的备用路径:正常情况,记作过程(5),以及 恢复路径,在一个独立的块中表示为恢复(6)两条替代路径 完全不同。正常情况下只有一个会被选中。spring-doc.cadn.net.cn

在特殊情况下(例如特殊情况)TranscationValidException类型),重试策略 可能能够确定恢复(6)最后一次尝试可以选择路径 后过程(5)只是失败了,而不是等待该项目被重新呈现。 这不是默认行为,因为它需要详细了解 发生在过程(5) 块,通常不存在。例如,如果 输出在失败前包含写入访问,例外应为 重新抛出以确保交易完整性。spring-doc.cadn.net.cn

外部完工政策重复(1)对 计划。如果输出(5.1)失败,可能会抛出异常(通常如此,因为 描述),在这种情况下,交易,德州(2),失败,例外可能 通过外层批次向上传播重复(1)我们不希望整批人都 停,因为重试(4)如果我们再试一次,仍然可能成功,所以我们加例外=非关键向外重复(1).spring-doc.cadn.net.cn

但请注意,如果德州(2)失败后,我们再次尝试,因为外部 完备策略,即下一个在内部处理的项目重复(3) 不是 肯定会是刚刚失败的那个。可能是,但这取决于 输入的实现(4.1)。因此,输出(5.1)可能在任一 新物品还是旧物品。批次的客户端不应假设每个重试(4) Attempt 会处理和上次失败的项目相同的内容。例如,如果 终止政策重复(1) 是尝试10次后失败,10次失败 连续尝试,但不一定是针对同一个物品。这与 总体重试策略。内层重试(4)了解每个项目的历史,且 可以决定是否再尝试一次。spring-doc.cadn.net.cn

异步块处理

典型示例中的内部批次或块可以执行 同时通过配置外部批处理使用异步任务执行器.外部 批处理则等待所有区块完成后再完成。以下示例显示 异步块处理:spring-doc.cadn.net.cn

1   |  REPEAT(until=exhausted, concurrent, exception=not critical) {
|
2   |    TX {
3   |      REPEAT(size=5) {
|
4   |        RETRY(stateful, exception=deadlock loser) {
4.1 |          input;
5   |        } PROCESS {
|          output;
6   |        } RECOVER {
|          recover;
|        }
|
|      }
|    }
|
|  }

异步项目处理

典型例子中,块中的单个项目也可以 原则是同时处理。在这种情况下,交易边界必须移动 到单个项目的层级,使得每笔交易都处于单一线程上,如 以下示例展示了:spring-doc.cadn.net.cn

1   |  REPEAT(until=exhausted, exception=not critical) {
|
2   |    REPEAT(size=5, concurrent) {
|
3   |      TX {
4   |        RETRY(stateful, exception=deadlock loser) {
4.1 |          input;
5   |        } PROCESS {
|          output;
6   |        } RECOVER {
|          recover;
|        }
|      }
|
|    }
|
|  }

该计划牺牲了简单方案中拥有所有条件的优化优势 交易资源被整合在一起。只有在成本 处理(5)远高于事务管理的成本(3)。spring-doc.cadn.net.cn

批处理与事务传播之间的相互作用

批处理重试和事务管理之间的联系比我们更紧密 理想情况下,喜欢。特别地,无状态重试不能用于重试数据库 作中带有不支持嵌套传播的事务管理器。spring-doc.cadn.net.cn

以下示例使用了无重复的重试:spring-doc.cadn.net.cn

1   |  TX {
|
1.1 |    input;
2.2 |    database access;
2   |    RETRY {
3   |      TX {
3.1 |        database access;
|      }
|    }
|
|  }

同样,出于同样的原因,内部交易,德州(3),可能导致外层 交易德州(1),即使重试(2)最终成功。spring-doc.cadn.net.cn

不幸的是,同样的效果会从重试区块蔓延到周围 如果有批次,请重复,如下示例所示:spring-doc.cadn.net.cn

1   |  TX {
|
2   |    REPEAT(size=5) {
2.1 |      input;
2.2 |      database access;
3   |      RETRY {
4   |        TX {
4.1 |          database access;
|        }
|      }
|    }
|
|  }

现在,如果TX(3)回滚,它可以污染TX(1)处的整个批次,强制它滚动 回到最后。spring-doc.cadn.net.cn

非默认传播呢?spring-doc.cadn.net.cn

  • 在上述例子中,PROPAGATION_REQUIRES_NEW德州(3) 防止外层德州(1)如果两笔交易最终都成功,则避免被污染。但如果德州(3) 提交 和德州(1) 回滚,德州(3) 保持承诺,因此我们违反了 交易合同德州(1)如果德州(3) 回滚,德州(1) 不一定会回滚 (但实际上可能确实有效,因为重试会抛出一个回滚异常)。spring-doc.cadn.net.cn

  • PROPAGATION_NESTED德州(3) 在重试情形下如我们所求般工作(且 带跳过的批次):德州(3) 可以提交但随后被外部回滚 交易德州(1)如果德州(3) 回滚,德州(1)在实践中回滚。这 该选项仅在部分平台上可用,不包括Hibernate或 JTA,但它是唯一一个始终稳定有效的。spring-doc.cadn.net.cn

因此,嵌 套如果重试块包含任何数据库,模式为最佳 访问。spring-doc.cadn.net.cn

特殊情况:正交资源交易

对于没有嵌套数据库的简单情况,默认传播总是可以的 交易。考虑以下例子,其中会期德州不是 全球XA资源,因此它们的资源是正交的:spring-doc.cadn.net.cn

0   |  SESSION {
1   |    input;
2   |    RETRY {
3   |      TX {
3.1 |        database access;
|      }
|    }
|  }

这里有一个事务性消息,会期(0),但不参与其他 与PlatformTransactionManager,因此当德州(3) 开始。除了重试(2)封锁。如果德州(3) 失败且 最终在重试中成功,会期(0) 可以提交(独立于德州封锁)。这类似于原版的“尽力而为,一阶段提交”的情景。这 最坏的情况是当重试(2) 成功且会期(0) 无法提交(例如,因为消息系统不可用)。spring-doc.cadn.net.cn

无州重试无法恢复

在前面典型的例子中,无状态重试和有状态重试的区别为 重要。实际上,最终是一个事务约束,迫使 这种区分,这个约束也说明了为什么会有这种区别。spring-doc.cadn.net.cn

我们从观察到无法跳过失败的项目开始, 除非我们用 a 包裹项目处理,否则成功提交剩余的部分 交易。因此,我们将典型的批执行计划简化为 遵循:spring-doc.cadn.net.cn

0   |  REPEAT(until=exhausted) {
|
1   |    TX {
2   |      REPEAT(size=5) {
|
3   |        RETRY(stateless) {
4   |          TX {
4.1 |            input;
4.2 |            database access;
|          }
5   |        } RECOVER {
5.1 |          skip;
|        }
|
|      }
|    }
|
|  }

前面的例子展示了无状态者重试(3) 带有恢复(5)踢腿的路径 在最终尝试失败之后。这无 国籍标签表示该块被重复 不重新抛出任何例外,直到某个极限。这仅在交易,德州(4),已实现传播嵌套。spring-doc.cadn.net.cn

如果德州(4)具有默认传播性质并回滚,会污染 外德州(1)事务管理器假设内部事务具有 导致事务资源损坏,因此无法再次使用。spring-doc.cadn.net.cn

支持嵌套繁殖的情况非常罕见,因此我们选择不支持 在当前版本的 Spring Batch 中实现了无状态重试的恢复。效果相同 总可以通过使用 这是之前展示的典型模式。spring-doc.cadn.net.cn