Spring Batch 2.1.8 中文文档(七)

4.2 Confinguring a JobRepository

之前说过,JobRepository是基本的CRUD操作,用于持久化Spring Batch的领域对象(如JobExecution,StepExecution)。许多主要的框架组件(如JobLauncher,Job,Step)都需要使用JobRepositor。batch的命名空间中已经抽象走许多JobRepository的实现细节,但是仍然需要一些配置:

<job-repository id="jobRepository"
    data-source="dataSource"
    transaction-manager="transactionManager"
    isolation-level-for-create="SERIALIZABLE"
    table-prefix="BATCH_"
	max-varchar-length="1000"
/>

上面列出的配置除了id外都是可选的。如果没有进行参数配置,默认值就是上面展示的内容,之所以写出来是用于展示给读者。max-varchar-length的默认值是2500,这表示varchar列的长度,sample schema scripts中用于存储类似于exit code这些描述的字符。如果你不修改schema并且也不会使用多字节编码,那么就不用修改它。

4.2.1 Transaction Configuration for the JobRepository

如果使用了namespace,repository会被自动加上事务控制,这是为了确保批处理操作元数据以及失败后重启的状态能够被准确的持久化,如果repository的方法不是事务控制的,那么框架的行为就不能够被准确的定义。create*方法的隔离级别会被单独指定,为了确保任务启动时,如果两个操作尝试在同时启动相同的任务,那么只有一个任务能够被成功启动。这种方法默认的隔离级别是SERIALIZABLE,这是相当激进的做法:READ_COMMITED能达到同样效果;如果两个操作不以这种方式冲突的话READ_UNCOMMITED也能很好工作。但是,由于调用create*方法是相当短暂的,只要数据库支持,就不会对性能产生太大影响。它也能被这样覆盖:

<job-repository id="jobRepository"
                isolation-level-for-create="REPEATABLE_READ" />

如果factory的namespace没有被使用,那么可以使用AOP来配置repository的事务行为:

<aop:config>
    <aop:advisor 
           pointcut="execution(* org.springframework.batch.core..*Repository+.*(..))"/>
    <advice-ref="txAdvice" />
</aop:config>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" />
    </tx:attributes>
</tx:advice>

这个配置片段基本上可以不做修改直接使用。记住加上适当的namespace描述去确保spring-tx和spring-aop(或是整个spring)都在classpath中。

4.2.2 Changing the Table Prefix

JobRepository可以修改的另一个属性是元数据表的表前缀。默认是以BATCH_开头,BATCH_JOB_EXECUTION和BATCH_STEP_EXECUTION就是两个例子。但是,有一些潜在的原因可能需要修改这个前缀。例如schema的名字需要被预置到表名中,或是不止一组的元数据表需要放在同一个schema中,那么表前缀就需要改变:

<job-repository id="jobRepository"
                table-prefix="SYSTEM.TEST_" />

按照上面的修改配置,每一个元数据查询都会带上SYSTEM.TEST_的前缀,BATCH_JOB_EXECUTION将会被更换为SYSTEM.TEST_JOB_EXECUTION。

备注:表名前缀是可配置的,表名和列名是不可配置的。

4.2.3 In-Memory Repository

有的时候不想把你的领域对象持久化到数据库中,可能是为了运行的更快速,因为每次提交都要开销额外的时间;也可能并不需要为特定任务保存状态。那么Spring Batch还提供了内存Map版本的job仓库:

<bean id="jobRepository" 
  class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
</bean>
需要注意的是内存Repository是轻量的并且不能在两个Jvm实例间重启任务,也不能允许同时启动带有相同参数的任务,不适合在多线程或是一个本地分片任务的场景下使用。而使用数据库版本的Repository则能够拥有这些特性。

但是也需要定义一个事务管理器,因为仓库需要回滚语义,也因为商业逻辑要求事务性(类似于RDBMS访问)。经过测试许多人觉得ResourcelessTransactionManager是很有用的。

4.2.4 Non-standard Database Types in Repository

如果使用的数据库平台不在支持的平台列表中,在SQL类型类似的情况下你可以使用近似的数据库类型。使用原生的JobRepositoryFactoryBean来取代命名空间缩写后设置一个相似的数据库类型:

<bean id="jobRepository" class="org...JobRepositoryFactoryBean">
    <property name="databaseType" value="db2"/>
    <property name="dataSource" ref="dataSource"/>
</bean>
(如果没有指定databaseType, JobRepositoryFactoryBean会通过datasource自动检测数据库的类型).平台之间的主要不同之处在于主键的计算策略,也可能需要覆盖incrementerFactory(使用Spring Framework提供的标准实现)。

如果它还不能工作,或是你不使用RDBMS,那么唯一的选择是让SimpleJobRepository使用spring方式依赖并且绑定在手工实现的各种dao接口上。

4.3 Configuring a JobLauncher

JobLauncher最基本的实现是SimpleJobLauncher,它唯一的依赖是通过JobRepository获取一个execution:

<bean id="jobLauncher"
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
</bean>
一旦获取到 JobExecution,那么可以通过执行Job的方法,最终将JobExecution返回给调用者:


从调度启动时,整个序列能够很好的直接工作,但是,从HTTP请求中启动则会出现一些问题。在这种场景中,启动任务需要异步操作,让SimpleJobLauncher能够立刻返回结果给调用者,如果让HTTP请求一直等待很长时间知道批处理任务完成获取到执行结果,是很糟糕的操作体验。一个流程如下图所示:


通过配置TaskExecutor可以很容易的将SimpleJobLauncher配置成异步操作:

<bean id="jobLauncher"
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
    <property name="taskExecutor">
        <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" />
    </property>
</bean>
TaskExecutor接口的任何实现都能够用来控制job的异步执行。

猜你喜欢

转载自blog.csdn.net/shorn/article/details/8002274