【问题标题】:JSR 352 Spring Batch: Transaction ManagementJSR 352 Spring Batch:事务管理
【发布时间】:2014-12-01 19:18:00
【问题描述】:

我尝试在 Websphere 中以 JSR 352 模式使用 Spring Batch。 (Websphere 8.0,Spring Batch 3.0.1)

据我了解文档,spring 应该处理事务,即在调用步骤的 ItemReader 之前开始事务,在调用 ItemWriter 之后提交事务等。

但是,在我的情况下,调用 ItemReader 时没有事务处于活动状态(userTransaction.getStatus() == 6)。如果我自己在 itemReader 中启动事务,我的代码就可以工作,但我的理解是我不应该这样做。

我怀疑问题出在我设置批次的方式上。

这是显示问题的示例代码:

META_INF/batch.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


<tx:jta-transaction-manager />

</beans>

META-INF/batch-jobs/samplebatch3.xml:

<?xml version="1.0" encoding="UTF-8"?>


<job version="1.0"
     id="samplebatch3" 
     xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd">
 <step id="step1">
     <chunk  checkpoint-policy="item"
            item-count="5">
            <reader ref="my.jbatchtest.samplebatch3.SampleReader" />
            <processor ref="my.jbatchtest.samplebatch3.SampleProcessor"/>
            <writer ref="my.jbatchtest.samplebatch3.SampleWriter" />
     </chunk> 
  </step>
</job>

ItemReader:

package my.jbatchtest.samplebatch3;

import java.io.Serializable;

import javax.batch.api.chunk.ItemReader;
import javax.naming.InitialContext;
import javax.transaction.UserTransaction;

import org.xadisk.connector.outbound.XADiskConnectionFactory;

public class SampleReader implements ItemReader {

    private UserTransaction utx;


    public SampleReader() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public void open(Serializable checkpoint) throws Exception {

        utx = (UserTransaction) new InitialContext().lookup("jta/usertransaction");   
        System.out.println("Status before begin:"+utx.getStatus());
        utx.begin();
        System.out.println("Status after begin:"+utx.getStatus());

    }

    @Override
    public void close() throws Exception {
        // TODO Auto-generated method stub

    }

    @Override
    public Object readItem() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Serializable checkpointInfo() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }

}

ItemReader 的调试输出:

[07.10.14 12:52:48:881 CEST] 00000039 SystemOut     O Status before begin:6
[07.10.14 12:52:48:881 CEST] 00000039 SystemOut     O Status after begin:0

我的问题是:

  1. 我的理解是否正确,Spring Batch 应该管理事务?
  2. 那为什么不这样做呢?

【问题讨论】:

    标签: java spring-batch websphere-8


    【解决方案1】:

    让我谈谈这里提出的一些问题。全面披露,我目前是 Spring Batch 的项目负责人,也是 JSR-352 专家组的成员。

    Spring Batch 和 JSR-352 的状态如何
    Spring Batch 自 3.0.0 版起符合 JSR-352 的所有 SE 要求。 JSR-352 的要求分为 SE 和 EE 组。我们没有解决规范中指定的与 Spring Batch 的“正常”处理不同的任何 EE 特性。

    为什么 Spring Batch 没有实现 EE 特有的功能?
    出于一个简单的原因,我们走上了只实现 SE 要求的路线。这些是我们可以通过可用的 TCK 验证是否符合规范的唯一要求。验证 EE 特定要求的唯一方法是将 TCK 作为应用程序服务器(Oracle 的 CTS)认证的一部分运行,Spring Batch 显然不是其中的一部分,也无法访问(假设它必须获得许可) .

    我们已经申请了一个可以验证 EE 功能的 TCK 版本,截至今天,我们收到的回复是 "In opening up the TCK for public contributions on GitHub, this is certainly an enhancement we'd be happy to accept help with."

    与任何优秀的开发人员一样,我们不想在没有测试的情况下开发新功能。我们希望能够验证我们实施的内容是否符合要求。在这种情况下,验证步骤在于针对我们的代码执行 TCK,这是我们目前无法做到的。无法执行 TCK 使我们面临以我们“认为”正确的方式实现 EE 功能的风险,释放它们,然后如果/当 TCK 可以运行时不得不改变它们的行为,这与直接矛盾JCP 试图提供的可移植性。

    BATCH-2240 怎么样?
    BATCH-2240 目前的情况不是要求修复 Spring Batch JSR-352 实现的行为方式。相反,它要求在事务中包装ItemStream#open()ItemStream#close() 方法的行为只会影响正常的Spring Batch 处理。修复 BATCH-2240 不会直接解决 Spring Batch 的 JSR-352 的行为方式。它被标记为小改进,因为它不被视为我们 JSR-352 实现中的错误,它被视为我们常规 Spring Batch 处理的附加功能。

    回答原始问题
    1. 我的理解正确吗,spring batch 应该管理事务? - 是的,你的理解是正确的。 Spring Batch 确实处理事务。使用基于块的步骤,在事务之外调用 open 和 close 方法,允许重置实现组件的状态。在 Spring Batch 中,没有什么可以阻止您使用 TransactionTemplate 将代码包装在事务中以获得类似的功能。
    2. 那为什么不这样做呢? - 我希望以上几点能解决这个问题。

    结论
    一旦我们有一种方法来验证我们已经以一种保证 JCP 试图实现的可移植性的方式解决了这些问题,我们就希望解决 JSR-352 的 EE 特定特性。我们认为正确的方法是拥有一个我们可以运行的标准化 TCK。一旦解决了这个问题,解决规范的 EE 版本和 Spring Batch 之间的差异将是一个高优先级。

    【讨论】:

    • 感谢您提供的信息。我们的意图是在尚不支持 JSR-352 (WAS 8.0) 的 JEE 环境中使用 SpringBatch,并在 JEE 7 实现后切换到本机 JSR-352 实现。在这个环境中,我们不使用其他 Spring 特性,也不打算使用。 (不是我的决定……)这不是一个创建高效代码的项目,而是公司中其他项目使用的模板和操作指南。您的信息肯定会帮助我们决定如何进行。
    【解决方案2】:

    在阅读并单步执行 Spring Batch 代码并阅读 JSR 352 规范后,我认为这可能是 Spring Batch 中的一个错误。

    我不喜欢将问题归咎于像 spring 这样经过良好测试的库,所以我仍然可能是错的。这是我发现的:

    Spring调用读写器的open()方法,然后执行读、处理、写的主批处理循环。完成循环后,在读写器上调用 close()。

    问题是,spring 批处理仅在事务上下文中运行主批处理循环。它不会为 open() 和 close() 调用启动事务。

    根据规范,这些调用应该在它们自己的事务中运行。这是来自 JSR 352 规范:

    11.6 Regular Chunk Processing
    
    1. <Create StepContext>
    2. <Store step level properties in StepContext>
    3. <->[StepListener.beforeStep...] // thread A
    4. [<begin transaction> ]
    5. <->ItemReader.open // thread A
    6. <->ItemWriter.open // thread A
    7. [<commit transaction> ]
    8. // chunk processing:
    9. <repeat until no more items> {
       a. <begin checkpoint [<begin transaction> ]>
       b. <repeat until commit criteria reached> {
            i. <->ItemReader.readItem // thread A
           ii. <->ItemProcessor.processItem // thread A
          iii. <add item to buffer>
       c. }
       d. <->ItemWriter.writeItems // thread A
       e. <->[ItemReader.checkpointInfo] // thread A
       f. <->[ItemWriter.checkpointInfo] // thread A
       g. <Store StepContext persistent area>
       h.
       i. <commit checkpoint (commit transaction)>
    10. }
    11. [<begin transaction> ]
    12. <->ItemWriter.close // thread A
    13. <->ItemReader.close // thread A
    14. [<commit transaction> ]
    15. <->[StepListener.afterStep...] // thread A
    16. <Store StepContext persistent area>
    17. <Destroy StepContext>
    

    第 4、7、11 和 14 行永远不会出现在 Spring Batch 中。

    我在我的代码中看到了这种行为(open() 和 close() 中没有打开事务),它也反映在 spring 批处理代码中:主循环明显的事务括号,open() 和没有事务代码关闭())

    我发现没有办法在 spring.io 网站上发布错误,只是一个指向 stackoverflow.com 的链接。也许 Spring 团队的某个人会看到这一点并给出一些反馈(或至少将其传递给开发人员)

    更新:这似乎是一个已知问题:https://jira.spring.io/browse/BATCH-2240 规范的符号似乎表明在这里启动事务是可选的,这使得编写读写器变得很麻烦,因为我必须检查我是否有一个有效的事务,并创建自己的事务括号是必要的。

    【讨论】:

    • 如果您认为存在错误,请注册 JIRA 问题。 Spring Batch 针对 Spring Batch TCK (afaik) 进行了测试,所以如果这是一个问题,它可能已经出现了。
    • @M.Deinum 感谢您的链接。这似乎确实是一个已知问题:jira.spring.io/browse/BATCH-2240。虽然我必须说我强烈不同意问题的优先级和类型:对明显违反规范的修复不是“小改进”。如果我需要围绕这个问题编写代码,我的代码将与符合标准的实现不兼容。
    • 好的,规范的符号似乎使它成为可选的,这使得分类正常。
    • 类别已由注册问题的人设置。如果您看到它已修复,请投票支持它,或提供补丁并发出拉取请求(显然已经存在,您可能希望在其中添加评论)。
    • 我刚刚投票了。至于提供补丁,我将不得不与我的客户核实他是否愿意为此付费。我想他只会告诉我解决这个问题。
    【解决方案3】:

    在你的 samplebatch3.xml 中,你需要在你的 step 和 chunk 标签之间声明一个 tasklet,并且在 tasklet 标签上,你引用了 Spring Batch 将使用的事务管理器,否则他不会知道使用哪个事务管理器.请参阅本页第 5.1.1 节:

    http://docs.spring.io/spring-batch/trunk/reference/html/configureStep.html

    已编辑:抱歉,我忘了你使用 jsr-352 而不是普通的 Spring 批处理,见下面的链接,它指定了一些你需要传递给框架的设置,其中之一是事务管理器

    http://docs.spring.io/spring-batch/trunk/reference/html/jsr-352.html

    在这篇文章中,有一个配置示例:

    https://blog.codecentric.de/en/2014/08/writing-jsr-352-style-jobs-spring-batch-part-1-configuration-options/

    参见“如何自定义标准配置”部分

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-19
      • 2019-10-14
      • 1970-01-01
      • 2021-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-07
      相关资源
      最近更新 更多