Announcement Announcement Module
Collapse
No announcement yet.
some class that I needed. Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • some class that I needed.

    Hi. Spring Batch is great. I read it Seriously.

    I Engaged in enterprise batch working.

    when I use it on my working, I writed two abstract class.

    for above:

    /*
    * Copyright 2006-2007 the original author or authors.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package cn.bestwiz.batch.database;

    import java.sql.SQLException;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;

    import org.springframework.batch.item.ClearFailedExceptio n;
    import org.springframework.batch.item.FlushFailedExceptio n;
    import org.springframework.batch.item.ItemWriter;
    import org.springframework.batch.item.database.ItemPrepar edStatementSetter;
    import org.springframework.batch.repeat.RepeatContext;
    import org.springframework.batch.repeat.support.RepeatSyn chronizationManager;
    import org.springframework.beans.factory.InitializingBean ;
    import org.springframework.orm.ibatis.SqlMapClientCallbac k;
    import org.springframework.orm.ibatis.SqlMapClientTemplat e;
    import org.springframework.transaction.support.Transactio nSynchronizationManager;
    import org.springframework.util.Assert;

    import com.ibatis.sqlmap.client.SqlMapExecutor;
    import com.mysql.jdbc.PreparedStatement;

    public abstract class AbstractIbatisItemWriter implements ItemWriter, InitializingBean {

    protected static final String ITEMS_PROCESSED = AbstractIbatisItemWriter.class.getName() + ".ITEMS_PROCESSED";

    private Set<Object> failed = new HashSet<Object>();

    private SqlMapClientTemplate sqlMapClientTemplate;

    public void afterPropertiesSet() throws Exception {
    Assert.notNull(sqlMapClientTemplate, "IbatisItemWriter requires an SqlMapClientTemplate.");
    }

    public void write(Object output) throws Exception {
    bindTransactionResources();
    getProcessed().add(output);
    flushIfNecessary(output);
    }

    private Set<Object> getProcessed() {
    Set processed = (Set)TransactionSynchronizationManager.getResource (ITEMS_PROCESSED);
    if (processed == null) {
    processed = Collections.EMPTY_SET;
    }
    return processed;
    }

    private void bindTransactionResources() {
    if (TransactionSynchronizationManager.hasResource(ITE MS_PROCESSED)) {
    return;
    }
    TransactionSynchronizationManager.bindResource(ITE MS_PROCESSED, new HashSet());
    }

    private void unbindTransactionResources() {
    if (!TransactionSynchronizationManager.hasResource(IT EMS_PROCESSED)) {
    return;
    }
    TransactionSynchronizationManager.unbindResource(I TEMS_PROCESSED);
    }

    private void flushIfNecessary(Object output) throws Exception {
    boolean flush;
    synchronized (failed) {
    flush = failed.contains(output);
    }
    if (flush) {
    RepeatContext context = RepeatSynchronizationManager.getContext();
    // Force early completion to commit aggressively if we encounter a
    // failed item (from a failed chunk but we don't know which one was
    // the problem).
    context.setCompleteOnly();
    // Flush now, so that if there is a failure this record can be
    // skipped.
    doFlush();
    }
    }

    private void doFlush() {
    final Set<Object> processed = getProcessed();
    try {
    if (!processed.isEmpty()) {
    sqlMapClientTemplate.execute(new SqlMapClientCallback() {

    public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
    executor.startBatch();
    for (Iterator<Object> iterator = processed.iterator(); iterator.hasNext() {
    Object item = (Object)iterator.next();
    doProcess(item);
    }
    return executor.executeBatch();
    }

    });
    }
    }
    catch (RuntimeException e) {
    synchronized (failed) {
    failed.addAll(processed);
    }
    throw e;
    }
    finally {
    getProcessed().clear();
    }
    }

    protected abstract void doProcess(Object item);

    public void clear() throws ClearFailedException {
    unbindTransactionResources();
    }

    public void flush() throws FlushFailedException {
    try {
    doFlush();
    }
    finally {
    unbindTransactionResources();
    }
    }

    }

    package cn.bestwiz.batch.database;

    import java.util.List;

    import org.springframework.batch.item.ExecutionContext;
    import org.springframework.batch.item.ExecutionContextUse rSupport;
    import org.springframework.batch.item.database.KeyCollect or;
    import org.springframework.orm.ibatis.SqlMapClientTemplat e;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;

    import com.ibatis.sqlmap.client.SqlMapClient;

    public abstract class AbstractIbatisKeyCollector extends ExecutionContextUserSupport implements KeyCollector {

    private static final String RESTART_KEY = "key.index";

    private SqlMapClientTemplate sqlMapClientTemplate;

    private String drivingQuery;

    private String restartQueryId;

    public AbstractIbatisKeyCollector() {
    setName(ClassUtils.getShortName(AbstractIbatisKeyC ollector.class));
    }

    public List<Object> retrieveKeys(ExecutionContext executionContext) {
    if (executionContext.containsKey(getKey(RESTART_KEY)) ) {
    Object key = executionContext.get(getKey(RESTART_KEY));
    return getRestartQueryId(restartQueryId, key);
    }
    else {
    return getDrivingQuery(drivingQuery);
    }
    }

    protected abstract List<Object> getRestartQueryId(String restartQueryId, Object key);

    protected abstract List<Object> getDrivingQuery(String drivingQuery);

    public void updateContext(Object key, ExecutionContext executionContext) {
    Assert.notNull(key, "Key must not be null");
    Assert.notNull(executionContext, "ExecutionContext must be null");
    executionContext.put(getKey(RESTART_KEY), key);
    }

    public void afterPropertiesSet() throws Exception {
    Assert.notNull(sqlMapClientTemplate, "SqlMaperClientTemplate must not be null.");
    Assert.hasText(drivingQuery, "The DrivingQuery must not be null or empty.");
    }

    public void setSqlMapClient(SqlMapClient sqlMapClient) {
    this.sqlMapClientTemplate = new SqlMapClientTemplate();
    this.sqlMapClientTemplate.setSqlMapClient(sqlMapCl ient);
    }

    public void setDrivingQueryId(String drivingQueryId) {
    this.drivingQuery = drivingQueryId;
    }

    public void setRestartQueryId(String restartQueryId) {
    this.restartQueryId = restartQueryId;
    }

    public final SqlMapClientTemplate getSqlMapClientTemplate() {
    return sqlMapClientTemplate;
    }

    }

    I hoped that spring batch framework can provide this kind of class for us, because I need some composite, custom operator, when I worked at enterprise. Maybe, I need one input, but I use it write to three table, when I update table, it may be affected 0 rows, I need to input a row record into this table. I want to say that many enterprise batch is composite, don't write code may be Impossible. I hope provide some class that I extends it simplly, I can finished my job easily.

  • #2
    If you could open JIRA issues for the ibatis support that would help you track the progress (a separate issue for the writer and the key collector would be best).

    I didn't understand the composite requirement. Maybe you could elaborate a little on what you job does in more detail?

    Comment


    • #3
      Dave Syer, Thank you for your answers.
      I use ibatis as my orm tools, I want to declare a keyCollector. I want to write keyCollector's sql in my ibatis sqlmap's xml, but the sql need some parameters. now, the IbatisKeyCollector class only provide setDrivingQueryId(String drivingQueryId) as setting sql's method, sometimes, I need this method: setDrivingQueryId(String drivingQueryId, Map parameters), because I don't want to write sql in my java code.
      In addition, In the case, If I read a item in the ItemReader, I write the item in ItemWriter. But the writing operation don't only be a sql, it may need to update five table, now BatchSqlUpdateItemWriter provide setSql(String sql) for ItemWriter's writing operation. sometimes I need this method: abstract doSimething(). I can't decide to do any things in the method, not only a sql operation.
      Please refer to the above questions, it may be not correct. I hope that spring batch will be more Powerful.

      Comment


      • #4
        where can I download the spring docs api? now, I only view it online.

        Comment


        • #5
          Originally posted by cuizuoli View Post
          where can I download the spring docs api? now, I only view it online.
          I think most people are fine with the source jars (your IDE should be able to display the javadocs from the source). If that doesn't work for you, you probably have to build the javadocs yourself from the sources.

          Comment


          • #6
            Originally posted by cuizuoli View Post
            I need this method: setDrivingQueryId(String drivingQueryId, Map parameters)
            How are you going to set the parameters? Configuration? That would be fine. I still suggest you open a JIRA issue.

            But the writing operation don't only be a sql, it may need to update five table... I can't decide to do any things in the method, not only a sql operation.
            Most people find that they can write a composite ItemWriter that delegates to other writers for cases like this. Usually there is some business logic to decide which of the 5 tables to update, so you need to write a custom item writer.

            Comment


            • #7
              OK, let me try it. Thank you very much.

              Comment


              • #8
                was a JIRA issue ever opened for the iBatis Item Reader?
                is it planned to be supported?

                Comment


                • #9
                  http://static.springframework.org/sp...temReader.html

                  http://static.springframework.org/sp...temReader.html

                  Comment


                  • #10
                    Thanks,
                    ofcourse i saw these classes but i was asking about the writer.
                    i think something like cuizuoli suggested might be useful since it's leveraging
                    iBatis' batch capabilities.

                    Comment


                    • #11
                      sorry, only now i see that in my first post i did mention item reader,
                      my mistake. ment to ask about iBatis item writer..

                      Comment


                      • #12
                        We haven't got any database ItemWriters right now because they are often quite application specific, and the ItemWriter interface is hard to get wrong - you just update the database (business specific) and don't really have to worry about anything else (transactions, restartability etc.). If you have a proposal for some features of an iBatis writer that make it generic and add some value over just implementing the interface we could look at including those.

                        Comment


                        • #13
                          could add value just the same as BatchSqlUpdateItemWriter does.

                          Code:
                          public class BatchIbatisUpdateItemWriter<T> implements ItemWriter<T>, InitializingBean {
                          
                                 ...
                          
                          	public void write(final List<? extends T> items) throws Exception {
                          
                          		if (!items.isEmpty()) {
                          
                          			int[] values = (int[]) sqlMapClientTemplate.execute(new SqlMapClientCallback() {
                          				public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {					
                          					executor.startBatch();
                          					for (T item : items) {
                          						executor.insert(queryId, item);
                          					}					
                          					List<BatchResult> detailed;
                          					try {
                          						detailed = executor.executeBatchDetailed();
                          					} catch (BatchException e) {
                          						throw new SQLException(e.getMessage() + " statement id:"+e.getFailingStatementId() + ", sql:"+e.getFailingSqlStatement() + ", batch exception:"+e.getBatchUpdateException());
                          					}
                          					return detailed.get(0).getUpdateCounts();					
                          				}
                          			});
                          			
                          			if (assertUpdates) {
                          				for (int i = 0; i < values.length; i++) {
                          					int value = values[i];
                          					if (value == 0) {
                          						throw new EmptyResultDataAccessException("Item " + i + " of " + values.length
                          								+ " did not update any rows: [" + items.get(i) + "]", 1);
                          					}
                          				}
                          			}
                          
                          		}
                          
                          	}
                          
                                 ...
                          
                          }

                          Comment


                          • #14
                            I see. If you sling that in a JIRA we can probably get it into 2.0 (especially if there is a test case).

                            Comment


                            • #15
                              http://jira.springframework.org/browse/BATCH-958

                              Comment

                              Working...
                              X