簡體   English   中英

Spring 批處理:使用自定義批處理大小將列表寫入數據庫表

[英]Spring Batch : Write a List to a database table using a custom batch size

背景

我有一個Spring 批處理作業,其中:

  1. FlatFileItemReader - 從文件中一次讀取一行
  2. ItemProcesor - 將文件中的行轉換為List<MyObject>並返回List 也就是說,文件中的每一行都分解為一個List<MyObject> (文件中的 1 行轉換為許多 output 行)。
  3. ItemWriter - 將List<MyObject>寫入數據庫表。 (我使用實現將收到的來自處理器和委托的列表解包到JdbcBatchItemWriter

問題

  • 在第 2 點)處理器可以返回一個包含 100000 個MyObject實例的List
  • 在第 3) 點,委托JdbcBatchItemWriter最終會將包含 100000 個對象的整個List寫入數據庫。

我的問題是: JdbcBatchItemWriter不允許自定義批量大小。 出於所有實際目的,該步驟的批大小 = 提交間隔。 考慮到這一點, Spring Batch中是否有另一個ItemWriter實現,它允許寫入數據庫並允許可配置的批量大小? 如果沒有,go 如何自己編寫自定義作家來實現這一目標?

我看不到在JdbcBatchItemWriter上設置批處理大小的明顯方法。 但是,您可以擴展編寫器並使用自定義BatchPreparedStatementSetter來指定批處理大小。 這是一個簡單的例子:

public class MyCustomWriter<T> extends JdbcBatchItemWriter<T> {

    @Override
    public void write(List<? extends T> items) throws Exception {
        namedParameterJdbcTemplate.getJdbcOperations().batchUpdate("your sql", new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                // set values on your sql
            }

            @Override
            public int getBatchSize() {
                return items.size(); // or any other value you want
            }
        });
    }

}

示例中的StagingItemWriter也是如何使用自定義BatchPreparedStatementSetter的示例。

Mahmoud Ben Hassine的答案和評論幾乎涵蓋了解決方案的所有方面,並且是公認的答案。

如果有人感興趣,這是我使用的實現:

public class JdbcCustomBatchSizeItemWriter<W> extends JdbcDaoSupport implements ItemWriter<W> {

    private int batchSize;
    private ParameterizedPreparedStatementSetter<W> preparedStatementSetter;
    private String sqlFileLocation;
    private String sql;

    public void initReader() {
        this.setSql(FileUtilties.getFileContent(sqlFileLocation));
    }

    public void write(List<? extends W> arg0) throws Exception {
        getJdbcTemplate().batchUpdate(sql, Collections.unmodifiableList(arg0), batchSize, preparedStatementSetter);
    }

    public void setBatchSize(int batchSize) {
        this.batchSize = batchSize;
    }

    public void setPreparedStatementSetter(ParameterizedPreparedStatementSetter<W> preparedStatementSetter) {
        this.preparedStatementSetter = preparedStatementSetter;
    }

    public void setSqlFileLocation(String sqlFileLocation) {
        this.sqlFileLocation = sqlFileLocation;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }
}

筆記:

  1. 使用Collections.unmodifiableList可以避免任何顯式轉換的需要。
  2. 我使用sqlFileLocation來指定一個包含 sql 的外部文件,而FileUtilities.getfileContents只返回這個 sql 文件的內容。 這可以跳過,也可以在創建 bean 時直接將sql傳遞給 class。

我不會這樣做的。 它提出了可重啟性的問題。 相反,修改您的閱讀器以生成單個項目,而不是讓您的處理器接收 object 並返回一個列表。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM