How to process logically related rows after ItemReader in SpringBatch?

前端 未结 5 2154
忘掉有多难
忘掉有多难 2020-12-15 05:51

Scenario

To make it simple, let\'s suppose I have an ItemReader that returns me 25 rows.

  1. The first 10 rows belong to student A

  2. The

5条回答
  •  一向
    一向 (楼主)
    2020-12-15 06:19

    In my application I created a CollectingJdbcCursorItemReader that extends the standard JdbcCursorItemReader and performs exactly what you need. Internally it uses my CollectingRowMapper: an extension of the standard RowMapper that maps multiple related rows to one object.

    Here is the code of the ItemReader, the code of CollectingRowMapper interface, and an abstract implementation of it, is available in another answer of mine.

    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    import org.springframework.batch.item.ReaderNotOpenException;
    import org.springframework.batch.item.database.JdbcCursorItemReader;
    import org.springframework.jdbc.core.RowMapper;
    
    /**
     * A JdbcCursorItemReader that uses a {@link CollectingRowMapper}.
     * Like the superclass this reader is not thread-safe.
     * 
     * @author Pino Navato
     **/
    public class CollectingJdbcCursorItemReader extends JdbcCursorItemReader {
    
        private CollectingRowMapper rowMapper;
        private boolean firstRead = true;
    
    
        /**
         * Accepts a {@link CollectingRowMapper} only.
         **/
        @Override
        public void setRowMapper(RowMapper rowMapper) {
            this.rowMapper = (CollectingRowMapper)rowMapper;
            super.setRowMapper(rowMapper);
         }
    
    
        /**
         * Read next row and map it to item.
         **/
        @Override
        protected T doRead() throws Exception {
            if (rs == null) {
                throw new ReaderNotOpenException("Reader must be open before it can be read.");
            }
    
            try {
                if (firstRead) {
                    if (!rs.next()) {  //Subsequent calls to next() will be executed by rowMapper
                        return null;
                    }
                    firstRead = false;
                } else if (!rowMapper.hasNext()) {
                    return null;
                }
                T item = readCursor(rs, getCurrentItemCount());
                return item;
            }
            catch (SQLException se) {
                throw getExceptionTranslator().translate("Attempt to process next row failed", getSql(), se);
            }
        }
    
        @Override
        protected T readCursor(ResultSet rs, int currentRow) throws SQLException {
            T result = super.readCursor(rs, currentRow);
            setCurrentItemCount(rs.getRow());
            return result;
        }
    
    }
    

    You can use it just like the classic JdbcCursorItemReader: the only requirement is that you provide it a CollectingRowMapper instead of the classic RowMapper.

提交回复
热议问题