|
对于最新稳定版本,请使用Spring Batch Documentation 6.0.0! |
批量处理与事务
简单批处理无重试
请考虑以下一个没有重试的嵌套批次示例。它显示了一个 批处理的常见场景:输入源被处理直到耗尽,且 它会在处理“块”结束时定期提交。
1 | REPEAT(until=exhausted) {
|
2 | TX {
3 | REPEAT(size=5) {
3.1 | input;
3.2 | output;
| }
| }
|
| }
输入作(3.1)可以是基于消息的接收(如来自JMS)或 基于文件的读取,但为了恢复并继续处理,有机会完成 整个工作,必须是交易性的。3.2版本的作也是如此。必须如此 要么是交易型,要么是幂零型。
如果块在重复(3) 由于数据库异常在3.2时失败,则德州(2)
必须回滚整个数据块。
简单无状态重试
对于非事务作使用重试也很有用,例如 调用Web服务或其他远程资源,如下示例所示:
0 | TX {
1 | input;
1.1 | output;
2 | RETRY {
2.1 | remote access;
| }
| }
这实际上是重试最有用的应用之一,因为远程调用是
比数据库更新更可能失败且可重试。只要遥控器
访问(2.1)最终成功,交易,德州(0),提交。如果遥控器
访问(2.1)最终失败,交易,德州(0),保证掷骰
返回。
典型的重复-重试模式
最常见的批处理模式是向 块,如下例子所示:
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) 如下:
-
抛出异常,回滚交易,
德州(2),在块级, 允许该项重新呈现到输入队列。 -
当该项目重新出现时,可能会根据现有的重试策略进行重试,且 执行
过程(5)再来一次。第二次及之后的尝试可能会再次失败, 重新抛出例外。 -
最终,该物品最后一次出现。重试政策不允许再尝试一次 尝试,所以
过程(5)从未被执行。在这种情况下,我们遵循恢复(6) 路径,实际上是“跳过”已接收并正在处理的项目。
注意所用的符号重试(4) 在计划中明确显示
输入步骤(4.1)是重试的一部分。同时也明确指出有两个
处理的备用路径:正常情况,记作过程(5),以及
恢复路径,在一个独立的块中表示为恢复(6)两条替代路径
完全不同。正常情况下只有一个会被选中。
在特殊情况下(例如特殊情况)TranscationValidException类型),重试策略
可能能够确定恢复(6)最后一次尝试可以选择路径
后过程(5)只是失败了,而不是等待该项目被重新呈现。
这不是默认行为,因为它需要详细了解
发生在过程(5) 块,通常不存在。例如,如果
输出在失败前包含写入访问,例外应为
重新抛出以确保交易完整性。
外部完工政策重复(1)对
计划。如果输出(5.1)失败,可能会抛出异常(通常如此,因为
描述),在这种情况下,交易,德州(2),失败,例外可能
通过外层批次向上传播重复(1)我们不希望整批人都
停,因为重试(4)如果我们再试一次,仍然可能成功,所以我们加例外=非关键向外重复(1).
但请注意,如果德州(2)失败后,我们会再次尝试,因为外部
完备策略,即下一个在内部处理的项目重复(3) 不是
肯定会是刚刚失败的那个。可能是,但这取决于
输入的实现(4.1)。因此,输出(5.1)可能在任一
新物品还是旧物品。批次的客户端不应假设每个重试(4)
Attempt 会处理和上次失败的项目相同的内容。例如,如果
终止政策重复(1) 是尝试10次后失败,10次失败
连续尝试,但不一定是针对同一个物品。这与
总体重试策略。内层重试(4)了解每个项目的历史,且
可以决定是否再尝试一次。
异步块处理
典型示例中的内部批次或块可以执行
同时通过配置外部批处理使用异步任务执行器.外部
批处理则等待所有区块完成后再完成。以下示例显示
异步块处理:
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;
| }
|
| }
| }
|
| }
异步项目处理
典型例子中,块中的单个项目也可以 原则是同时处理。在这种情况下,交易边界必须移动 到单个项目的层级,使得每笔交易都处于单一线程上,如 以下示例展示了:
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)。
批处理与事务传播之间的相互作用
批处理重试和事务管理之间的联系比我们更紧密 理想情况下,喜欢。特别地,无状态重试不能用于重试数据库 作中带有不支持嵌套传播的事务管理器。
以下示例使用了无重复的重试:
1 | TX {
|
1.1 | input;
2.2 | database access;
2 | RETRY {
3 | TX {
3.1 | database access;
| }
| }
|
| }
同样,出于同样的原因,内部交易,德州(3),可能导致外层
交易德州(1),即使重试(2)最终成功。
不幸的是,同样的效果会从重试区块蔓延到周围 如果有批次,请重复,如下示例所示:
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)处的整个批次,强制它滚动 回到最后。
非默认传播呢?
-
在上述例子中,
PROPAGATION_REQUIRES_NEW在德州(3) 防止外层德州(1)如果两笔交易最终都成功,则避免被污染。但如果德州(3) 提交 和德州(1) 回滚,德州(3) 保持承诺,因此我们违反了 交易合同德州(1)如果德州(3) 回滚,德州(1) 不一定会回滚 (但实际上可能确实有效,因为重试会抛出一个回滚异常)。 -
PROPAGATION_NESTED在德州(3) 在重试情形下如我们所求般工作(且 带跳过的批次):德州(3) 可以提交但随后被外部回滚 交易德州(1)如果德州(3) 回滚,德州(1)在实践中回滚。这 该选项仅在部分平台上可用,不包括Hibernate或 JTA,但它是唯一一个始终稳定有效的。
因此,嵌 套如果重试块包含任何数据库,模式为最佳
访问。
特殊情况:正交资源交易
对于没有嵌套数据库的简单情况,默认传播总是可以的
交易。考虑以下例子,其中会期和德州不是
全球XA资源,因此它们的资源是正交的:
0 | SESSION {
1 | input;
2 | RETRY {
3 | TX {
3.1 | database access;
| }
| }
| }
这里有一个事务性消息,会期(0),但不参与其他
与PlatformTransactionManager,因此当德州(3)
开始。除了重试(2)封锁。如果德州(3) 失败且
最终在重试中成功,会期(0) 可以提交(独立于德州封锁)。这类似于原版的“尽力而为,一阶段提交”的情景。这
最坏的情况是当重试(2) 成功且会期(0) 无法提交(例如,因为消息系统不可用)。
无州重试无法恢复
在前面典型的例子中,无状态重试和有状态重试的区别为 重要。实际上,最终是一个事务约束,迫使 这种区分,这个约束也说明了为什么会有这种区别。
我们从观察到无法跳过失败的项目开始, 除非我们用 a 包裹项目处理,否则成功提交剩余的部分 交易。因此,我们将典型的批执行计划简化为 遵循:
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),已实现传播嵌套。
如果德州(4)具有默认传播性质并回滚,会污染
外德州(1)事务管理器假设内部事务具有
导致事务资源损坏,因此无法再次使用。
支持嵌套繁殖的情况非常罕见,因此我们选择不支持 在当前版本的 Spring Batch 中实现了无状态重试的恢复。效果相同 总可以通过使用 这是之前展示的典型模式。