我尝试在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 /分批作业/ 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
我的问题是:
答案 0 :(得分:7)
让我谈谈在这里提出的一些问题。完全披露,我目前是Spring Batch的项目负责人,我也是JSR-352的专家组。
Spring Batch和JSR-352的状态是什么
版本3.0.0的Spring Batch符合JSR-352标准,适用于所有SE要求。 JSR-352的要求分为SE和EE分组。我们没有解决规范中规定的与Spring Batch&#34; normal&#34;处理
为什么没有Spring Batch实现EE特定功能?
出于一个简单的原因,我们走了仅实施SE要求的路线。这些是我们可以通过可用的TCK验证符合规范的唯一要求。验证EE特定要求的唯一方法是将TCK作为应用程序服务器(Oracle的CTS)认证的一部分运行,Spring Batch显然不是其中的一部分,也不具有访问权限(鉴于此必须获得许可)。
我们已经要求TCK的一个版本,我们可以验证EE功能,截至今天,我们收到的回复是"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确实处理事务。使用基于块的步骤,在事务外部调用open和close方法,允许重置实现组件的状态。在Spring Batch中,没有什么可以阻止您使用TransactionTemplate
在事务中包装代码以获得类似的功能
2. 那为什么不这样做? - 我希望以上几点能解决这个问题。
<强>结论强>
一旦我们有办法验证我们已经以保证JCP尝试实现的可移植性的方式解决了它们,我们想要解决JSR-352的EE特定功能。我们认为,正确的方法是拥有一个我们可以运行的标准化TCK。一旦解决了这个问题,解决规范的EE版本和Spring Batch之间的差异将是一个高优先级。
答案 1 :(得分:1)
在阅读并单步执行弹簧批处理代码并阅读JSR 352规范后,我认为这可能是春季批处理中的一个错误。
我不喜欢像春天这样对经过良好测试的图书馆指责问题,所以我仍然可能错了。这是我发现的:
Spring调用reader和writer的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和4行永远不会发生在春季批次中。
我在我的代码中看到了这种行为(open()和close()中没有打开的事务),它也反映在spring批处理代码中:主循环的明显事务括号,open()没有事务代码和关闭())
我发现无法在spring.io网站上发布错误,只是指向stackoverflow.com的链接。也许来自Spring团队的人会看到这个并提供一些反馈(或者至少将其传递给开发人员)
Upate :这似乎是一个众所周知的问题:https://jira.spring.io/browse/BATCH-2240 规范的表示法似乎表明在这里开始一个事务是可选的,这使编码读者和编写者很麻烦,因为我必须检查我是否有一个有效的事务,并且创建我自己的事务括号是必要的。
答案 2 :(得分:1)
在你的samplebatch3.xml上,你需要在你的步骤和块标签之间声明一个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
在本文中,有一个配置示例:
请参阅“如何自定义标准配置”
部分