Skip to content

Instantly share code, notes, and snippets.

@bmchild
Created February 18, 2015 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bmchild/fb8f84df9f6c66e04f0d to your computer and use it in GitHub Desktop.
Save bmchild/fb8f84df9f6c66e04f0d to your computer and use it in GitHub Desktop.
Custom Batch Save Repository
package com.bmchild.data.shared.batch;
import javax.sql.DataSource;
import org.apache.commons.lang.Validate;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author bchild
*
*/
public abstract class AbstractBatchCustomRepositoryImpl {
private JdbcTemplate jdbcTemplate = null;
protected int executeBatch(String sql, BatchPreparedStatementSetter batchPreparedStatementSetter) {
Validate.notNull(jdbcTemplate, "Datasource not set for batch statement.");
int[] rows = jdbcTemplate.batchUpdate(sql, batchPreparedStatementSetter);
return sumRows(rows);
}
private int sumRows(int[] rows) {
int rowCount = 0;
for(int row : rows) {
rowCount += row;
}
return rowCount;
}
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
}
package com.bmchild.data.shared.batch;
import java.util.Collection;
/**
*
* @author brettchild
*
* @param <T>
*/
public interface BatchSaveCustomRepository<T> {
/**
* @param records
* @return number of records saved
*/
int batchSave(Collection<T> records);
}
package com.bmchild.data.cti.repository;
import java.util.Date;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import com.bmchild.data.shared.batch.BatchSaveCustomRepository;
/*
* Our Repository get the default functionality of the JPARepository plus we all also add our batchSave.
* If we wanted to also add a batch update we could make a batch update interface and implement that in our concrete impl class
*/
public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, BatchSaveCustomRepository<MyEntity> {
}
package com.bmchild.data.cti.repository;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import com.bmchild.data.shared.batch.AbstractBatchCustomRepositoryImpl;
import com.bmchild.data.shared.batch.BatchSaveCustomRepository;
import com.bmchild.data.shared.common.util.CollectionUtil;
/*
* Impl of our repo so we can add our batch save functionality
*/
public class MyEntityRepositoryImpl extends AbstractBatchCustomRepositoryImpl implements BatchSaveCustomRepository<MyEntity> {
private static final String BATCH_INSERT_SQL = "insert into myentity (field1, field2) "
+ " VALUES (?, ?)";
/* We limit the number of records we process at a time to avoid too many parameters per query */
private static final Integer BATCH_SIZE = 500;
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
@PostConstruct
public void postConstruct() {
setDataSource(dataSource);
}
@Override
public int batchSave(Collection<MyEntity> records) {
int count = 0;
for(final List<MyEntity> batch : CollectionUtil.split(records, BATCH_SIZE)) {
count += executeBatch(BATCH_INSERT_SQL, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
MyEntity l = batch.get(i);
ps.setString(1, l.getField1());
ps.setString(2, l.getField2());
}
@Override
public int getBatchSize() {
return batch.size();
}
});
}
return count;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment