BATCH-760: refactoring, moving SQL snippets to PagingQueryProvider implementations, adding some database specific implementations (more to come)
This commit is contained in:
@@ -1,6 +1,22 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 org.springframework.batch.item.database;
|
||||
|
||||
import org.springframework.batch.item.support.AbstractItemReaderItemStream;
|
||||
import org.springframework.batch.item.database.support.PagingQueryProvider;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -9,9 +25,6 @@ import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
@@ -25,12 +38,13 @@ import java.sql.SQLException;
|
||||
* {@link org.springframework.batch.item.ItemReader} for reading database records using JDBC in a paging
|
||||
* fashion.
|
||||
*
|
||||
* It executes the SQL built from values specified for {@link #setSelectClause(String)} (String)},
|
||||
* {@link #setFromClause(String)} (String)} and {@link #setWhereClause(String)} (String)} to retrieve requested data.
|
||||
* The query is executed using paged requests of a size specified in {@link #setPageSize(int)}. Additional pages
|
||||
* are requested when needed as {@link #read()} method is called, returning an object corresponding to current position.
|
||||
* It executes the SQL built by the {@link PagingQueryProvider} to retrieve requested data.
|
||||
* The query is executed using paged requests of a size specified in {@link #setPageSize(int)}.
|
||||
* Additional pages are requested when needed as {@link #read()} method is called, returning an
|
||||
* object corresponding to current position.
|
||||
*
|
||||
* The performance of the paging depends on the database specific features available to limit the number of returned rows.
|
||||
* The performance of the paging depends on the database specific features available to limit the number
|
||||
* of returned rows.
|
||||
*
|
||||
* Setting a fairly large page size and using a commit interval that matches the page size should provide
|
||||
* better performance.
|
||||
@@ -46,22 +60,12 @@ public class JdbcPagingItemReader<T> extends AbstractItemReaderItemStream<T> imp
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private PagingQueryProvider queryProvider;
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
private ParameterizedRowMapper<T> parameterizedRowMapper;
|
||||
|
||||
private String databaseProductName;
|
||||
|
||||
private String selectClause;
|
||||
|
||||
private String fromClause;
|
||||
|
||||
private String whereClause;
|
||||
|
||||
private String sortKey;
|
||||
|
||||
private String orderClause;
|
||||
|
||||
private String firstPageSql;
|
||||
|
||||
private String remainingPagesSql;
|
||||
@@ -86,53 +90,8 @@ public class JdbcPagingItemReader<T> extends AbstractItemReaderItemStream<T> imp
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selectClause SELECT clause part of SQL query string
|
||||
*/
|
||||
public void setSelectClause(String selectClause) {
|
||||
String keyWord = "select ";
|
||||
String temp = selectClause.trim();
|
||||
if (temp.toLowerCase().startsWith(keyWord) && temp.length() > keyWord.length()) {
|
||||
this.selectClause = temp.substring(keyWord.length());
|
||||
}
|
||||
else {
|
||||
this.selectClause = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fromClause FROM clause part of SQL query string
|
||||
*/
|
||||
public void setFromClause(String fromClause) {
|
||||
String keyWord = "from ";
|
||||
String temp = fromClause.trim();
|
||||
if (temp.toLowerCase().startsWith(keyWord) && temp.length() > keyWord.length()) {
|
||||
this.fromClause = temp.substring(keyWord.length());
|
||||
}
|
||||
else {
|
||||
this.fromClause = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param whereClause WHERE clause part of SQL query string
|
||||
*/
|
||||
public void setWhereClause(String whereClause) {
|
||||
String keyWord = "where ";
|
||||
String temp = whereClause.trim();
|
||||
if (temp.toLowerCase().startsWith(keyWord) && temp.length() > keyWord.length()) {
|
||||
this.whereClause = temp.substring(keyWord.length());
|
||||
}
|
||||
else {
|
||||
this.whereClause = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sortKey key to use to sort and limit page content
|
||||
*/
|
||||
public void setSortKey(String sortKey) {
|
||||
this.sortKey = sortKey;
|
||||
public void setQueryProvider(PagingQueryProvider queryProvider) {
|
||||
this.queryProvider = queryProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -159,59 +118,15 @@ public class JdbcPagingItemReader<T> extends AbstractItemReaderItemStream<T> imp
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(dataSource);
|
||||
Assert.hasLength(selectClause, "selectClause must be specified");
|
||||
Assert.hasLength(fromClause, "fromClause must be specified");
|
||||
Assert.hasLength(sortKey, "sortKey must be specified");
|
||||
Assert.isTrue(pageSize > 0, "pageSize must be greater than zero");
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
jdbcTemplate.setMaxRows(pageSize);
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(jdbcTemplate);
|
||||
initializeSqlStatements();
|
||||
Assert.notNull(queryProvider);
|
||||
this.firstPageSql = queryProvider.generateFirstPageQuery(pageSize);
|
||||
this.remainingPagesSql = queryProvider.generateRemainingPagesQuery(pageSize);
|
||||
}
|
||||
|
||||
private void initializeSqlStatements() throws MetaDataAccessException {
|
||||
this.databaseProductName = JdbcUtils.commonDatabaseName(
|
||||
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName").toString());
|
||||
String topClause = "";
|
||||
String limitCondition = "";
|
||||
String limitClause = "";
|
||||
if ("DB2".equals(databaseProductName)) {
|
||||
limitClause = " FETCH FIRST " + pageSize + " ROWS ONLY";
|
||||
}
|
||||
else if ("Oracle".equals(databaseProductName)) {
|
||||
limitCondition = "ROWNUM <= " + pageSize;
|
||||
}
|
||||
else if ("MySQL".equals(databaseProductName) || "PostgreSQL".equals(databaseProductName)) {
|
||||
limitClause = " LIMIT " + pageSize;
|
||||
}
|
||||
else if ("Microsoft SQL Server".equals(databaseProductName) || "Sybase".equals(databaseProductName) ||
|
||||
"HSQL Database Engine".equals(databaseProductName)) {
|
||||
topClause = "TOP " + pageSize + " ";
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
String version = JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseVersion").toString();
|
||||
if ("10.4.1.3".compareTo(version) > 0) {
|
||||
throw new InvalidDataAccessResourceUsageException(databaseProductName + " version " + version + " is not supported");
|
||||
}
|
||||
// Derby doesn't support TOP or LIMIT -- maxRows will limit the rows retrieved
|
||||
}
|
||||
else {
|
||||
throw new InvalidDataAccessResourceUsageException(databaseProductName + " is not a supported database");
|
||||
}
|
||||
this.orderClause = " ORDER BY SORT_KEY";
|
||||
this.firstPageSql = "SELECT " + topClause + selectClause + ", " + sortKey + " AS SORT_KEY" +
|
||||
" FROM " + fromClause +
|
||||
(whereClause == null ? "" : " WHERE " + whereClause) +
|
||||
(limitCondition.length() == 0 ? "" : (whereClause == null ? " WHERE " : " AND ") + limitCondition) +
|
||||
orderClause + limitClause;
|
||||
this.remainingPagesSql = "SELECT " + topClause + selectClause + ", " + sortKey + " AS SORT_KEY" +
|
||||
" FROM " + fromClause + " WHERE " + sortKey + " > ?" +
|
||||
(whereClause == null ? "" : " AND " + whereClause) +
|
||||
(limitCondition.length() == 0 ? "" : " AND " + limitCondition) +
|
||||
orderClause + limitClause;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T doRead() throws Exception {
|
||||
@@ -289,35 +204,13 @@ public class JdbcPagingItemReader<T> extends AbstractItemReaderItemStream<T> imp
|
||||
page = itemIndex / pageSize;
|
||||
current = itemIndex % pageSize;
|
||||
|
||||
int offset = (page * pageSize) - 1;
|
||||
int lastRowNum = (page * pageSize);
|
||||
|
||||
logger.debug("Jumping to page " + page + " and index " + current);
|
||||
|
||||
if (page > 0) {
|
||||
|
||||
String windowClause = "";
|
||||
String topClause = "";
|
||||
String limitClause = "";
|
||||
if ("DB2".equals(databaseProductName) || "Oracle".equals(databaseProductName) ||
|
||||
"Microsoft SQL Server".equals(databaseProductName) || "Sybase".equals(databaseProductName) ||
|
||||
"Apache Derby".equals(databaseProductName)) {
|
||||
windowClause = "ROW_NUMBER() OVER (ORDER BY " + sortKey + " ASC) AS ROW_NUMBER";
|
||||
}
|
||||
else if ("HSQL Database Engine".equals(databaseProductName)) {
|
||||
topClause = "LIMIT " + offset + " 1 ";
|
||||
}
|
||||
else if ("MySQL".equals(databaseProductName) || "PostgreSQL".equals(databaseProductName) ||
|
||||
"HSQL Database Engine".equals(databaseProductName)) {
|
||||
limitClause = " LIMIT 1 OFFSET " + offset;
|
||||
}
|
||||
String jumpToItemSql;
|
||||
|
||||
String jumpToItemSql =
|
||||
(windowClause.length() > 0 ? "SELECT * FROM ( " : "") +
|
||||
"SELECT " + (topClause.length() > 0 ? topClause : "") + sortKey + " AS SORT_KEY" +
|
||||
(windowClause.length() > 0 ? ", " + windowClause : "") +
|
||||
" FROM " + fromClause + (whereClause == null ? "" : " WHERE " + whereClause) +
|
||||
(windowClause.length() > 0 ? ") WHERE ROW_NUMBER = " + lastRowNum : orderClause + limitClause);
|
||||
jumpToItemSql = queryProvider.generateJumpToItemQuery(itemIndex, pageSize);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SQL used for jumping: [" + jumpToItemSql + "]");
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 org.springframework.batch.item.database.support;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Abstract SQL Paging Query Provider to serve as a base class for all provided SQL paging query providers.
|
||||
*
|
||||
* Any implementation must provide a way to specify the select clause, from clause and optionally a where clause.
|
||||
* In addition a way to specify a single column sort key must also be provided. This sort key will be used to
|
||||
* provide the paging functinality. It is recommended that there should be an index for the sort key to provide
|
||||
* better performance.
|
||||
*
|
||||
* Provides properties and preperation for the mandatory "selectClause" and "fromClause" as well as for the
|
||||
* optional "whereClause". Also provides property for the mandatory "sortKey".
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractSqlPagingQueryProvider implements PagingQueryProvider {
|
||||
|
||||
private String selectClause;
|
||||
|
||||
private String fromClause;
|
||||
|
||||
private String whereClause;
|
||||
|
||||
private String sortKey;
|
||||
|
||||
/**
|
||||
* @param selectClause SELECT clause part of SQL query string
|
||||
*/
|
||||
public void setSelectClause(String selectClause) {
|
||||
String keyWord = "select ";
|
||||
String temp = selectClause.trim();
|
||||
if (temp.toLowerCase().startsWith(keyWord) && temp.length() > keyWord.length()) {
|
||||
this.selectClause = temp.substring(keyWord.length());
|
||||
}
|
||||
else {
|
||||
this.selectClause = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the
|
||||
*/
|
||||
protected String getSelectClause() {
|
||||
return selectClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fromClause FROM clause part of SQL query string
|
||||
*/
|
||||
public void setFromClause(String fromClause) {
|
||||
String keyWord = "from ";
|
||||
String temp = fromClause.trim();
|
||||
if (temp.toLowerCase().startsWith(keyWord) && temp.length() > keyWord.length()) {
|
||||
this.fromClause = temp.substring(keyWord.length());
|
||||
}
|
||||
else {
|
||||
this.fromClause = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getFromClause() {
|
||||
return fromClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param whereClause WHERE clause part of SQL query string
|
||||
*/
|
||||
public void setWhereClause(String whereClause) {
|
||||
String keyWord = "where ";
|
||||
String temp = whereClause.trim();
|
||||
if (temp.toLowerCase().startsWith(keyWord) && temp.length() > keyWord.length()) {
|
||||
this.whereClause = temp.substring(keyWord.length());
|
||||
}
|
||||
else {
|
||||
this.whereClause = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getWhereClause() {
|
||||
return whereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sortKey key to use to sort and limit page content
|
||||
*/
|
||||
public void setSortKey(String sortKey) {
|
||||
this.sortKey = sortKey;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getSortKey() {
|
||||
return sortKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check mandatory properties.
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void init(DataSource dataSource) throws Exception {
|
||||
Assert.notNull(dataSource);
|
||||
Assert.hasLength(selectClause, "selectClause must be specified");
|
||||
Assert.hasLength(fromClause, "fromClause must be specified");
|
||||
Assert.hasLength(sortKey, "sortKey must be specified");
|
||||
}
|
||||
|
||||
public abstract String generateFirstPageQuery(int pageSize);
|
||||
|
||||
public abstract String generateRemainingPagesQuery(int pageSize);
|
||||
|
||||
public abstract String generateJumpToItemQuery(int itemIndex, int pageSize);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 org.springframework.batch.item.database.support;
|
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Derby implementation of a {@link PagingQueryProvider} using standard SQL:2003 windowing functions.
|
||||
* These features are supported starting with Apache Derby version 10.4.1.3.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
*/
|
||||
public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider {
|
||||
|
||||
@Override
|
||||
public void init(DataSource dataSource) throws Exception {
|
||||
super.init(dataSource);
|
||||
String version = JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion").toString();
|
||||
if ("10.4.1.3".compareTo(version) > 0) {
|
||||
throw new InvalidDataAccessResourceUsageException("Apache Derby version " + version + " is not supported by this class, Only version 10.4.1.3 or later is supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 org.springframework.batch.item.database.support;
|
||||
|
||||
/**
|
||||
* MySQL implementation of a {@link org.springframework.batch.item.database.support.PagingQueryProvider} using database specific features.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HsqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
|
||||
|
||||
@Override
|
||||
public String generateFirstPageQuery(int pageSize) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT ").append("TOP ").append(pageSize).append(" ").append(getSelectClause());
|
||||
sql.append(" FROM ").append(getFromClause());
|
||||
sql.append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRemainingPagesQuery(int pageSize) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT ").append("TOP ").append(pageSize).append(" ").append(getSelectClause());
|
||||
sql.append(" FROM ").append(getFromClause());
|
||||
sql.append(" WHERE ").append(getSortKey()).append(" > ?");
|
||||
sql.append(getWhereClause() == null ? "" : " AND " + getWhereClause());
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
|
||||
int page = itemIndex / pageSize;
|
||||
int offset = (page * pageSize) - 1;
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT LIMIT ").append(offset).append(" 1 ").append(getSortKey()).append(" AS SORT_KEY");
|
||||
sql.append(" FROM ").append(getFromClause());
|
||||
sql.append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2006-2008 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 org.springframework.batch.item.database.support;
|
||||
|
||||
/**
|
||||
* MySQL implementation of a {@link PagingQueryProvider} using database specific features.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MySqlPagingQueryProvider extends AbstractSqlPagingQueryProvider {
|
||||
|
||||
@Override
|
||||
public String generateFirstPageQuery(int pageSize) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT ").append(getSelectClause());
|
||||
sql.append(" FROM ").append(getFromClause());
|
||||
sql.append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
|
||||
sql.append(" LIMIT ").append(pageSize);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateRemainingPagesQuery(int pageSize) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT ").append(getSelectClause());
|
||||
sql.append(" FROM ").append(getFromClause());
|
||||
sql.append(" WHERE ").append(getSortKey()).append(" > ?");
|
||||
sql.append(getWhereClause() == null ? "" : " AND " + getWhereClause());
|
||||
sql.append(" LIMIT ").append(pageSize);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
|
||||
int page = itemIndex / pageSize;
|
||||
int offset = (page * pageSize) - 1;
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT ").append(getSortKey()).append(" AS SORT_KEY");
|
||||
sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
|
||||
sql.append(" LIMIT ").append(offset).append(" 1");
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,41 +15,39 @@
|
||||
*/
|
||||
package org.springframework.batch.item.database.support;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
/**
|
||||
* Interface defining the functionality to be provided for generating paging queries for use with JDBC.
|
||||
*
|
||||
* Any usage must provide the select clause, from clause and optionally a where clause. In addition a
|
||||
* single column sort key must be defined. This sort key will be used to provide the paging functinality.
|
||||
* It is recommended that there should be an index for the sort key to provide better performance.
|
||||
* Interface defining the functionality to be provided for generating paging queries for use with Paging
|
||||
* Item Readers.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface JdbcPagingQueryProvider {
|
||||
public interface PagingQueryProvider {
|
||||
|
||||
/**
|
||||
* Initialize the query provider using the provided {@link DataSource} if necessary.
|
||||
*
|
||||
* @param dataSource DataSource to use for any initialization
|
||||
*/
|
||||
void init(DataSource dataSource) throws Exception;
|
||||
|
||||
/**
|
||||
* Generate the query that will provide the first page, limited by the page size.
|
||||
*
|
||||
* @param pageSize number of rows to read for each page
|
||||
* @param selectClause the columns that are part of the selct clause
|
||||
* @param fromClause the table(s) that are part of the from clause
|
||||
* @param whereClause the conditions that are part of the where clause
|
||||
* @param sortKey the single column used for sorting
|
||||
* @return the generated query
|
||||
*/
|
||||
String generateFirstPageQuery(int pageSize, String selectClause, String fromClause, String whereClause, String sortKey);
|
||||
String generateFirstPageQuery(int pageSize);
|
||||
|
||||
/**
|
||||
* Generate the query that will provide the first page, limited by the page size.
|
||||
*
|
||||
* @param pageSize number of rows to read for each page
|
||||
* @param selectClause the columns that are part of the selct clause
|
||||
* @param fromClause the table(s) that are part of the from clause
|
||||
* @param whereClause the conditions that are part of the where clause
|
||||
* @param sortKey the single column used for sorting
|
||||
* @return the generated query
|
||||
*/
|
||||
String generateRemainingPagesQuery(int pageSize, String selectClause, String fromClause, String whereClause, String sortKey);
|
||||
String generateRemainingPagesQuery(int pageSize);
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -59,12 +57,8 @@ public interface JdbcPagingQueryProvider {
|
||||
*
|
||||
* @param itemIndex the index for the next item to be read
|
||||
* @param pageSize number of rows to read for each page
|
||||
* @param selectClause the columns that are part of the selct clause
|
||||
* @param fromClause the table(s) that are part of the from clause
|
||||
* @param whereClause the conditions that are part of the where clause
|
||||
* @param sortKey the single column used for sorting
|
||||
* @return the generated query
|
||||
*/
|
||||
String generateJumpToItemQuery(int itemIndex, int pageSize, String selectClause, String fromClause, String whereClause, String sortKey);
|
||||
String generateJumpToItemQuery(int itemIndex, int pageSize);
|
||||
|
||||
}
|
||||
@@ -22,40 +22,40 @@ package org.springframework.batch.item.database.support;
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SqlWindowingPagingQueryProvider implements JdbcPagingQueryProvider {
|
||||
public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvider {
|
||||
|
||||
public String generateFirstPageQuery(int pageSize, String selectClause, String fromClause, String whereClause, String sortKey) {
|
||||
public String generateFirstPageQuery(int pageSize) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT * FROM ( ");
|
||||
sql.append("SELECT ").append(selectClause).append(", ");
|
||||
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(sortKey).append(" ASC) AS ROW_NUMBER");
|
||||
sql.append(" FROM ").append(fromClause).append(whereClause == null ? "" : " WHERE " + whereClause);
|
||||
sql.append("SELECT ").append(getSelectClause()).append(", ");
|
||||
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey()).append(" ASC) AS ROW_NUMBER");
|
||||
sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
|
||||
sql.append(") WHERE ROW_NUMBER <= ").append(pageSize);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
public String generateRemainingPagesQuery(int pageSize, String selectClause, String fromClause, String whereClause, String sortKey) {
|
||||
public String generateRemainingPagesQuery(int pageSize) {
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT * FROM ( ");
|
||||
sql.append("SELECT ").append(selectClause).append(", ");
|
||||
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(sortKey).append(" ASC) AS ROW_NUMBER");
|
||||
sql.append(" FROM ").append(fromClause).append(" WHERE ").append(sortKey).append(" > ?");
|
||||
sql.append(whereClause == null ? "" : " AND " + whereClause);
|
||||
sql.append("SELECT ").append(getSelectClause()).append(", ");
|
||||
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey()).append(" ASC) AS ROW_NUMBER");
|
||||
sql.append(" FROM ").append(getFromClause()).append(" WHERE ").append(getSortKey()).append(" > ?");
|
||||
sql.append(getWhereClause() == null ? "" : " AND " + getWhereClause());
|
||||
sql.append(") WHERE ROW_NUMBER <= ").append(pageSize);
|
||||
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
public String generateJumpToItemQuery(int itemIndex, int pageSize, String selectClause, String fromClause, String whereClause, String sortKey) {
|
||||
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
|
||||
int page = itemIndex / pageSize;
|
||||
int lastRowNum = (page * pageSize);
|
||||
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("SELECT SORT_KEY FROM ( ");
|
||||
sql.append("SELECT ").append(sortKey).append(" AS SORT_KEY, ");
|
||||
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(sortKey).append(" ASC) AS ROW_NUMBER");
|
||||
sql.append(" FROM ").append(fromClause).append(whereClause == null ? "" : " WHERE " + whereClause);
|
||||
sql.append("SELECT ").append(getSortKey()).append(" AS SORT_KEY, ");
|
||||
sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey()).append(" ASC) AS ROW_NUMBER");
|
||||
sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
|
||||
sql.append(") WHERE ROW_NUMBER = ").append(lastRowNum);
|
||||
|
||||
return sql.toString();
|
||||
|
||||
Reference in New Issue
Block a user