Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从多个源读取Spring批处理作业_Java_Database_Spring_Spring Batch - Fatal编程技术网

Java 从多个源读取Spring批处理作业

Java 从多个源读取Spring批处理作业,java,database,spring,spring-batch,Java,Database,Spring,Spring Batch,如何从多个数据库中读取项目?我已经从文件中知道这是可能的。 以下示例适用于从多个文件读取 ... <job id="readMultiFileJob" xmlns="http://www.springframework.org/schema/batch"> <step id="step1"> <tasklet> <chunk reader="multiResourceReader" writer="flatFileItem

如何从多个数据库中读取项目?我已经从文件中知道这是可能的。
以下示例适用于从多个文件读取

...
<job id="readMultiFileJob" xmlns="http://www.springframework.org/schema/batch">
    <step id="step1">
    <tasklet>
        <chunk reader="multiResourceReader" writer="flatFileItemWriter"
            commit-interval="1" />
    </tasklet>
    </step>
</job>
...
<bean id="multiResourceReader"
    class=" org.springframework.batch.item.file.MultiResourceItemReader">
    <property name="resources" value="file:csv/inputs/domain-*.csv" />
    <property name="delegate" ref="flatFileItemReader" />
</bean>
...
。。。
...
...

三颗这样的豆子

<bean id="database2" class="org.springframework.batch.item.database.JdbcCursorItemReader">
    <property name="name" value="database2Reader" />
    <property name="dataSource" ref="dataSource2" />
    <property name="sql" value="select image from object where image like '%/images/%'" />
    <property name="rowMapper">
        <bean class="sym.batch.ImagesRowMapper2" />
    </property>
</bean>

没有现成的组件可以执行您的要求;唯一的解决方案是编写一个自定义的
ItemReader
,它委托给
JdbcCursorItemReader
(或
HibernateCursorItemReader
或任何通用的
ItemReader
实现)。
您需要准备所有必要的资料(数据源、会话、真正的数据库读取器),并将所有委托读取器绑定到自定义读取器。

编辑: 您需要使用
ItemReader.read()
和mantain reader和delegates状态的循环来模拟作业重启期间的循环

class MyItemReader<T> implements ItemReader<T>, ItemStream {
  private ItemReader[] delegates;
  private int delegateIndex;
  private ItemReader<T> currentDelegate;
  private ExecutionContext stepExecutionContext;

  public void setDelegates(ItemReader[] delegates) {
    this.delegates = delegates;
  }

  @BeforeStep
  private void beforeStep(StepExecution stepExecution) {
    this.stepExecutionContext = stepExecution.getExecutionContext();
  }

  public T read() {
    T item = null;
    if(null != currentDelegate) {
      item = currentDelegate.read();
      if(null == item) {
        ((ItemStream)this.currentDelegate).close();
        this.currentDelegate = null;
      }
    }
    // Move to next delegate if previous was exhausted!
    if(null == item && this.delegateIndex< this.delegates.length) {
      this.currentDelegate = this.delegates[this.currentIndex++];
      ((ItemStream)this.currentDelegate).open(this.stepExecutionContext);
      update(this.stepExecutionContext);
      // Recurse to read() to simulate loop through delegates
      item = read();
    }
    return item;
  }

  public void open(ExecutionContext ctx) {
    // During open restore last active reader and restore its state
    if(ctx.containsKey("index")) {
      this.delegateIndex = ctx.getInt("index");
      this.currentDelegate = this.delegates[this.delegateIndex];
      ((ItemStream)this.currentDelegate ).open(ctx);
    }
  }

  public void update(ExecutionContext ctx) {
    // Update current delegate index and state
    ctx.putInt("index", this.delegateIndex);
    if(null != this.currentDelegate) {
      ((ItemStream)this.currentDelegate).update(ctx);
    }
  }

  public void close(ExecutionContext ctx) {
    if(null != this.currentDelegate) {
      ((ItemStream)this.currentDelegate).close();
  }
}
MyItemReader类实现ItemReader、ItemStream{ 私人项目阅读器[]代表; 私有整数委托索引; 私人委托; 私有ExecutionContext步骤ExecutionContext; 公共void集合委托(ItemReader[]委托){ 这个。代表=代表; } @先于 私有void beforeStep(步骤执行步骤执行){ this.stepExecutionContext=stepExecution.getExecutionContext(); } 公众阅读{ T项=null; 如果(null!=currentDelegate){ item=currentDelegate.read(); if(null==项){ ((ItemStream)this.currentDelegate).close(); this.currentDelegate=null; } } //如果上一个代理已用尽,则移动到下一个代理! if(null==item&&this.delegateIndex


EDIT2:记住设置属性名称;这是让MyItemReader.read()正常工作所必需的

<bean id="itemReader1" class="JdbcCursorItemReader">
  <property name="name" value="itemReader1" />
  <!-- Set other properties -->
</bean>

我建议使用一种巧妙的方法。如果我们假设一个是mysql数据源的表,该表中的每一行都对应于其他mysql数据源表的行(如位于不同数据源中的联接表),则可以在批处理作业itemreader中执行此操作。例如

Spring数据源配置

<bean id="mySqlDataSource1" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${database1.driverClassName}"/>
    <property name="url" value="${database1.url}"/>
    <property name="username" value="${database1.username}"/>
    <property name="password" value="${database1.password}"/>
    <property name="validationQuery" value="${database1.validationQuery}"/>
</bean>

<bean id="mySqlDataSource2" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${database2.driverClassName}"/>
    <property name="url" value="${database2.url}"/>
    <property name="username" value="${database2.username}"/>
    <property name="password" value="${database2.password}"/>
    <property name="validationQuery" value="${database2.validationQuery}"/>
</bean>

您的batch-job.xml

<bean id="multiDatasorceReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step">
    <property name="dataSource" ref="mySqlDataSource1" />
    <property name="rowMapper" ref="multiDatasourceRowMapper" />
    <property name="sql">
        <value>
            SELECT * FROM xyz
        </value>
    </property>
</bean>

<bean id="multiDatasourceRowMapper" class="yourpackage.MultiDatasourceRowMapper" scope="step">
    <property name="secondDataSource" ref="mySqlDataSource2" />
    <property name="secondSql">
        <value>
            SELECT * FROM abc
        </value>
    </property>
</bean>

从xyz中选择*
从abc中选择*
您的RowMapper看起来像

public class MultiDatasourceRowMapper implements RowMapper<String> {

    private DataSource secondDataSource;

    private String secondSql;

    public String mapRow(ResultSet rs, int arg1) throws SQLException {
        Connection conn = secondDataSource.getConnection();
        PreparedStatement prep = conn.prepareStatement(secondSql); 

        // Do Something

        return "";
    }

    public void setSecondDataSource(DataSource secondDataSource) {
        this.secondDataSource = secondDataSource;
    }

    public void setSecondSql(String secondSql) {
        this.secondSql = secondSql;
    }

}
public类MultiDatasourceRowMapper实现行映射器{
私有数据源第二数据源;
私有字符串;
公共字符串mapRow(ResultSet rs,int arg1)引发SQLException{
Connection conn=secondDataSource.getConnection();
PreparedStatement prep=conn.prepareStatement(secondSql);
//做点什么
返回“”;
}
public void setSecondDataSource(数据源第二数据源){
this.secondDataSource=secondDataSource;
}
公共void setSecondSql(字符串secondSql){
this.secondSql=secondSql;
}
}

我建议一种简单的解决方法,它可能不适用于所有情况,但在许多情况下都很有用:

简单定义:

  • 2个读卡器,每个数据库一个
  • 2步
  • 一个包含两个步骤的作业
这两个步骤几乎相同,它们引用相同的处理器和写入程序,但它们有不同的读卡器。它们将被连续调用


此设置是否有效取决于处理器和写入程序(在不同步骤中调用时,它们是否仍能正常工作)。在我的例子中,对编写器设置
appendAllowed=true
就足够了,这样两个步骤都可以写入同一个文件。

您可以提供更多关于您的情况的信息吗?例如;-您是否从相同的数据库类型(MySQL、Oracle或DB2)读取数据?-你们从不同的数据库实例中读取相同的表吗?若答案是否定的,你们如何将你们的输入映射到相同的对象?MySQL是否有不同的表,我只想取一个字符串
public class MultiDatasourceRowMapper implements RowMapper<String> {

    private DataSource secondDataSource;

    private String secondSql;

    public String mapRow(ResultSet rs, int arg1) throws SQLException {
        Connection conn = secondDataSource.getConnection();
        PreparedStatement prep = conn.prepareStatement(secondSql); 

        // Do Something

        return "";
    }

    public void setSecondDataSource(DataSource secondDataSource) {
        this.secondDataSource = secondDataSource;
    }

    public void setSecondSql(String secondSql) {
        this.secondSql = secondSql;
    }

}