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.


{
Reply With Quote
