INT-2260: JdbcPollingChA: rename prop to maxRows

JIRA: https://jira.spring.io/browse/INT-2260

Having a feedback about confusing with the `max-rows-per-poll` property
name and its responsibility it would be better do not mention `per-poll`
at all

* Deprecate `max-rows-per-poll` in favor of new `max-rows`
* Some code style polishing, tests improvements
* Docs polishing on the matter

* Add `What's New` bullet

* Optimize `maxRows` logic
* Document vendor-specific native SELECT limiting options
* Raise warning in the parsers about deprecated `max-rows-per-poll`

Doc polishing
This commit is contained in:
Artem Bilan
2018-06-14 17:53:25 -04:00
committed by Gary Russell
parent 5a362b62ff
commit 32030c3233
12 changed files with 247 additions and 158 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -44,14 +44,13 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
private final JdbcPollingChannelAdapter poller;
private volatile SqlParameterSourceFactory sqlParameterSourceFactory =
new ExpressionEvaluatingSqlParameterSourceFactory();
private SqlParameterSourceFactory sqlParameterSourceFactory = new ExpressionEvaluatingSqlParameterSourceFactory();
private volatile boolean sqlParameterSourceFactorySet;
private boolean sqlParameterSourceFactorySet;
private volatile boolean keysGenerated;
private boolean keysGenerated;
private volatile Integer maxRowsPerPoll;
private Integer maxRows;
public JdbcOutboundGateway(DataSource dataSource, String updateQuery) {
this(new JdbcTemplate(dataSource), updateQuery, null);
@@ -66,16 +65,16 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
}
public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery, String selectQuery) {
Assert.notNull(jdbcOperations, "'jdbcOperations' must not be null.");
if (!StringUtils.hasText(updateQuery) && !StringUtils.hasText(selectQuery)) {
throw new IllegalArgumentException("The 'updateQuery' and the 'selectQuery' must not both be null or empty.");
throw new IllegalArgumentException(
"The 'updateQuery' and the 'selectQuery' must not both be null or empty.");
}
if (StringUtils.hasText(selectQuery)) {
this.poller = new JdbcPollingChannelAdapter(jdbcOperations, selectQuery);
this.poller.setMaxRowsPerPoll(1);
this.poller.setMaxRows(1);
}
else {
this.poller = null;
@@ -98,10 +97,54 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
* This parameter is only applicable if a selectQuery was provided. Null values
* are not permitted.
* @param maxRowsPerPoll the number of rows to select. Must not be null.
* @deprecated since 5.1 in favor of {@link #setMaxRows(Integer)}
*/
@Deprecated
public void setMaxRowsPerPoll(Integer maxRowsPerPoll) {
Assert.notNull(maxRowsPerPoll, "MaxRowsPerPoll must not be null.");
this.maxRowsPerPoll = maxRowsPerPoll;
setMaxRows(maxRowsPerPoll);
}
/**
* The maximum number of rows to query.
* The value is ultimately set on the underlying {@link JdbcPollingChannelAdapter}.
* If not specified this value will default to {@code 1}.
* This parameter is only applicable if a selectQuery was provided. Null values
* are not permitted.
* @param maxRows the number of rows to select. Must not be null.
* @since 5.1
* @see JdbcPollingChannelAdapter#setMaxRows(int)
*/
public void setMaxRows(Integer maxRows) {
Assert.notNull(maxRows, "'maxRows' must not be null.");
this.maxRows = maxRows;
}
/**
* Flag to indicate that the update query is an insert with auto-generated keys,
* which will be logged at debug level.
* @param keysGenerated the flag value to set
*/
public void setKeysGenerated(boolean keysGenerated) {
this.keysGenerated = keysGenerated;
}
public void setRequestSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
Assert.notNull(this.handler, "'handler' cannot be null");
this.handler.setSqlParameterSourceFactory(sqlParameterSourceFactory);
}
public void setRequestPreparedStatementSetter(MessagePreparedStatementSetter requestPreparedStatementSetter) {
Assert.notNull(this.handler, "'handler' cannot be null");
this.handler.setPreparedStatementSetter(requestPreparedStatementSetter);
}
public void setReplySqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
this.sqlParameterSourceFactory = sqlParameterSourceFactory;
this.sqlParameterSourceFactorySet = true;
}
public void setRowMapper(RowMapper<?> rowMapper) {
this.poller.setRowMapper(rowMapper);
}
@Override
@@ -111,9 +154,9 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
@Override
protected void doInit() {
if (this.maxRowsPerPoll != null) {
Assert.notNull(this.poller, "If you want to set 'maxRowsPerPoll', then you must provide a 'selectQuery'.");
this.poller.setMaxRowsPerPoll(this.maxRowsPerPoll);
if (this.maxRows != null) {
Assert.notNull(this.poller, "If you want to set 'maxRows', then you must provide a 'selectQuery'.");
this.poller.setMaxRows(this.maxRows);
}
if (this.handler != null) {
@@ -167,31 +210,4 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
return payload;
}
/**
* Flag to indicate that the update query is an insert with auto-generated keys, which will be logged at debug level.
* @param keysGenerated the flag value to set
*/
public void setKeysGenerated(boolean keysGenerated) {
this.keysGenerated = keysGenerated;
}
public void setRequestSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
Assert.notNull(this.handler, "'handler' cannot be null");
this.handler.setSqlParameterSourceFactory(sqlParameterSourceFactory);
}
public void setRequestPreparedStatementSetter(MessagePreparedStatementSetter requestPreparedStatementSetter) {
Assert.notNull(this.handler, "'handler' cannot be null");
this.handler.setPreparedStatementSetter(requestPreparedStatementSetter);
}
public void setReplySqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterSourceFactory) {
this.sqlParameterSourceFactory = sqlParameterSourceFactory;
this.sqlParameterSourceFactorySet = true;
}
public void setRowMapper(RowMapper<?> rowMapper) {
this.poller.setRowMapper(rowMapper);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -16,8 +16,9 @@
package org.springframework.integration.jdbc;
import java.util.ArrayList;
import java.sql.PreparedStatement;
import java.util.List;
import java.util.function.Consumer;
import javax.sql.DataSource;
@@ -25,13 +26,15 @@ import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.core.MessageSource;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.RowMapperResultSetExtractor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
/**
* A polling channel adapter that creates messages from the payload returned by
@@ -50,42 +53,55 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen
private final String selectQuery;
private volatile RowMapper<?> rowMapper;
private RowMapper<?> rowMapper;
private volatile SqlParameterSource sqlQueryParameterSource;
private SqlParameterSource sqlQueryParameterSource;
private volatile boolean updatePerRow = false;
private boolean updatePerRow = false;
private volatile String updateSql;
private String updateSql;
private volatile SqlParameterSourceFactory sqlParameterSourceFactory =
new ExpressionEvaluatingSqlParameterSourceFactory();
private SqlParameterSourceFactory sqlParameterSourceFactory = new ExpressionEvaluatingSqlParameterSourceFactory();
private volatile boolean sqlParameterSourceFactorySet;
private boolean sqlParameterSourceFactorySet;
private volatile int maxRowsPerPoll = 0;
private int maxRows = 0;
/**
* Constructor taking {@link DataSource} from which the DB Connection can be
* obtained and the select query to execute to retrieve new rows.
*
* @param dataSource Must not be null
* @param selectQuery query to execute
*/
public JdbcPollingChannelAdapter(DataSource dataSource, String selectQuery) {
this.jdbcOperations = new NamedParameterJdbcTemplate(dataSource);
this.selectQuery = selectQuery;
this(new JdbcTemplate(dataSource), selectQuery);
}
/**
* Constructor taking {@link JdbcOperations} instance to use for query
* execution and the select query to execute to retrieve new rows.
*
* @param jdbcOperations instance to use for query execution
* @param selectQuery query to execute
*/
public JdbcPollingChannelAdapter(JdbcOperations jdbcOperations, String selectQuery) {
this.jdbcOperations = new NamedParameterJdbcTemplate(jdbcOperations);
Assert.hasText(selectQuery, "'selectQuery' must be specified.");
this.jdbcOperations = new NamedParameterJdbcTemplate(jdbcOperations) {
@Override
protected PreparedStatementCreator getPreparedStatementCreator(String sql,
SqlParameterSource paramSource, Consumer<PreparedStatementCreatorFactory> customizer) {
PreparedStatementCreator preparedStatementCreator =
super.getPreparedStatementCreator(sql, paramSource, customizer);
return con -> {
PreparedStatement preparedStatement = preparedStatementCreator.createPreparedStatement(con);
preparedStatement.setMaxRows(JdbcPollingChannelAdapter.this.maxRows);
return preparedStatement;
};
}
};
this.selectQuery = selectQuery;
}
@@ -108,7 +124,6 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen
/**
* A source of parameters for the select query used for polling.
*
* @param sqlQueryParameterSource the sql query parameter source to set
*/
public void setSelectSqlParameterSource(SqlParameterSource sqlQueryParameterSource) {
@@ -119,22 +134,37 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen
* The maximum number of rows to pull out of the query results per poll (if
* greater than zero, otherwise all rows will be packed into the outgoing
* message). Default is zero.
*
* @param maxRows the max rows to set
* @deprecated since 5.1 in favor of {@link #setMaxRows(int)}
*/
@Deprecated
public void setMaxRowsPerPoll(int maxRows) {
this.maxRowsPerPoll = maxRows;
setMaxRows(maxRows);
}
/**
* The maximum number of rows to query. Default is zero - select all records.
* @param maxRows the max rows to set
* @since 5.1
*/
public void setMaxRows(int maxRows) {
this.maxRows = maxRows;
}
@Override
protected void onInit() throws Exception {
super.onInit();
if (!this.sqlParameterSourceFactorySet && this.getBeanFactory() != null) {
if (!this.sqlParameterSourceFactorySet && getBeanFactory() != null) {
((ExpressionEvaluatingSqlParameterSourceFactory) this.sqlParameterSourceFactory)
.setBeanFactory(this.getBeanFactory());
.setBeanFactory(getBeanFactory());
}
}
@Override
public String getComponentType() {
return "jdbc:inbound-channel-adapter";
}
/**
* Execute the query. If a query result set contains one or more rows, the
* Message payload will contain either a List of Maps for each row or, if a
@@ -148,7 +178,9 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen
if (payload == null) {
return null;
}
return this.getMessageBuilderFactory().withPayload(payload).build();
return getMessageBuilderFactory()
.withPayload(payload)
.build();
}
/**
@@ -174,43 +206,20 @@ public class JdbcPollingChannelAdapter extends IntegrationObjectSupport implemen
return payload;
}
protected List<?> doPoll(SqlParameterSource sqlQueryParameterSource) {
final RowMapper<?> rowMapper = this.rowMapper == null ? new ColumnMapRowMapper() : this.rowMapper;
if (sqlQueryParameterSource != null) {
return this.jdbcOperations.query(this.selectQuery, sqlQueryParameterSource, rowMapper);
}
else {
return this.jdbcOperations.query(this.selectQuery, rowMapper);
}
}
private void executeUpdateQuery(Object obj) {
SqlParameterSource updateParameterSource = this.sqlParameterSourceFactory.createParameterSource(obj);
this.jdbcOperations.update(this.updateSql, updateParameterSource);
}
protected List<?> doPoll(SqlParameterSource sqlQueryParameterSource) {
final RowMapper<?> rowMapper = this.rowMapper == null ? new ColumnMapRowMapper() : this.rowMapper;
ResultSetExtractor<List<Object>> resultSetExtractor;
if (this.maxRowsPerPoll > 0) {
resultSetExtractor = rs -> {
List<Object> results = new ArrayList<Object>(JdbcPollingChannelAdapter.this.maxRowsPerPoll);
int rowNum = 0;
while (rs.next() && rowNum < JdbcPollingChannelAdapter.this.maxRowsPerPoll) {
results.add(rowMapper.mapRow(rs, rowNum++));
}
return results;
};
}
else {
@SuppressWarnings("unchecked")
ResultSetExtractor<List<Object>> temp =
new RowMapperResultSetExtractor<Object>((RowMapper<Object>) rowMapper);
resultSetExtractor = temp;
}
if (sqlQueryParameterSource != null) {
return this.jdbcOperations.query(this.selectQuery, sqlQueryParameterSource, resultSetExtractor);
}
else {
return this.jdbcOperations.getJdbcOperations().query(this.selectQuery, resultSetExtractor);
}
}
@Override
public String getComponentType() {
return "jdbc:inbound-channel-adapter";
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
@@ -71,22 +71,36 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element,
"request-prepared-statement-setter");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "row-mapper");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
// TODO remove deprecated option in the next version
boolean hasMaxRowsPerPoll = element.hasAttribute("max-rows-per-poll");
boolean hasMaxRows = element.hasAttribute("max-rows");
if (hasMaxRowsPerPoll) {
parserContext.getReaderContext()
.warning("The 'max-rows-per-poll' is deprecated in favor of 'max-rows'", element);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
if (hasMaxRows) {
parserContext.getReaderContext()
.warning("The 'max-rows' has a precedence over 'max-rows-per-poll'", element);
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "keys-generated");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
String replyChannel = element.getAttribute("reply-channel");
if (StringUtils.hasText(replyChannel)) {
builder.addPropertyReference("outputChannel", replyChannel);
}
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
return builder;
}
@Override
protected String getInputChannelAttributeName() {
return "request-channel";
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -19,7 +19,6 @@ package org.springframework.integration.jdbc.config;
import org.w3c.dom.Element;
import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
@@ -28,9 +27,11 @@ import org.springframework.integration.jdbc.JdbcPollingChannelAdapter;
import org.springframework.util.StringUtils;
/**
* Parser for {@link org.springframework.integration.jdbc.JdbcPollingChannelAdapter}.
* Parser for {@link JdbcPollingChannelAdapter}.
*
* @author Jonas Partner
* @author Artem Bilan
*
* @since 2.0
*/
public class JdbcPollingChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
@@ -59,9 +60,9 @@ public class JdbcPollingChannelAdapterParser extends AbstractPollingInboundChann
}
String query = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "query", parserContext);
if (!StringUtils.hasText(query)) {
throw new BeanCreationException("The query attrbitue is required");
parserContext.getReaderContext()
.error("The 'query' attribute is required", element);
}
String update = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "update", parserContext);
if (refToDataSourceSet) {
builder.addConstructorArgReference(dataSourceRef);
}
@@ -69,14 +70,32 @@ public class JdbcPollingChannelAdapterParser extends AbstractPollingInboundChann
builder.addConstructorArgReference(jdbcOperationsRef);
}
builder.addConstructorArgValue(query);
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "row-mapper");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "update-sql-parameter-source-factory");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "select-sql-parameter-source");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
if (update != null) {
builder.addPropertyValue("updateSql", update);
// TODO remove deprecated option in the next version
boolean hasMaxRowsPerPoll = element.hasAttribute("max-rows-per-poll");
boolean hasMaxRows = element.hasAttribute("max-rows");
if (hasMaxRowsPerPoll) {
parserContext.getReaderContext()
.warning("The 'max-rows-per-poll' is deprecated in favor of 'max-rows'", element);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
if (hasMaxRows) {
parserContext.getReaderContext()
.warning("The 'max-rows' has a precedence over 'max-rows-per-poll'", element);
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "update", "updateSql");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "update-per-row");
return builder.getBeanDefinition();
}

View File

@@ -174,9 +174,17 @@
<xsd:attribute name="max-rows-per-poll" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Limits the number of rows extracted per query (otherwise all rows
are extracted into the
outgoing message).
[DEPRECATED] Limits the number of rows extracted per query (otherwise all rows
are extracted into the outgoing message).
Deprecated since 5.1 in favor of 'max-rows'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="max-rows" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Limits the number of rows extracted per query.
Otherwise all rows are extracted into the outgoing message.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
@@ -360,13 +368,24 @@
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="max-rows-per-poll" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
[DEPRECATED] When using a select query, you can set a
custom limit regarding the number of rows
extracted. Otherwise by default only the first
row will be extracted into the outgoing message.
If set to '0' all rows are extracted.
Deprecated since 5.1 in favor of 'max-rows'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="max-rows" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
When using a select query, you can set a
custom limit regarding the number of rows
extracted. Otherwise by default only the first
row will be extracted into the outgoing message.
If set to '0' all rows are extracted.
</xsd:documentation>
</xsd:annotation>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -60,14 +60,14 @@ public class JdbcOutboundGatewayTests {
JdbcOutboundGateway jdbcOutboundGateway = new JdbcOutboundGateway(dataSource, "update something");
try {
jdbcOutboundGateway.setMaxRowsPerPoll(10);
jdbcOutboundGateway.setMaxRows(10);
jdbcOutboundGateway.setBeanFactory(mock(BeanFactory.class));
jdbcOutboundGateway.afterPropertiesSet();
fail("Expected an IllegalArgumentException to be thrown.");
}
catch (IllegalArgumentException e) {
assertEquals("If you want to set 'maxRowsPerPoll', then you must provide a 'selectQuery'.", e.getMessage());
assertEquals("If you want to set 'maxRows', then you must provide a 'selectQuery'.", e.getMessage());
}
dataSource.shutdown();
@@ -99,7 +99,8 @@ public class JdbcOutboundGatewayTests {
fail("Expected an IllegalArgumentException to be thrown.");
}
catch (IllegalArgumentException e) {
Assert.assertEquals("The 'updateQuery' and the 'selectQuery' must not both be null or empty.", e.getMessage());
Assert.assertEquals("The 'updateQuery' and the 'selectQuery' must not both be null or empty.",
e.getMessage());
}
}
@@ -108,12 +109,12 @@ public class JdbcOutboundGatewayTests {
JdbcOutboundGateway jdbcOutboundGateway = new JdbcOutboundGateway(dataSource, "select * from DOES_NOT_EXIST");
try {
jdbcOutboundGateway.setMaxRowsPerPoll(null);
jdbcOutboundGateway.setMaxRows(null);
fail("Expected an IllegalArgumentException to be thrown.");
}
catch (IllegalArgumentException e) {
assertEquals("MaxRowsPerPoll must not be null.", e.getMessage());
assertEquals("'maxRows' must not be null.", e.getMessage());
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -204,7 +204,7 @@ public class JdbcPollingChannelAdapterIntegrationTests {
"select * from item where id not in (select id from copy)");
adapter.setUpdateSql("insert into copy values(:id,10)");
adapter.setUpdatePerRow(true);
adapter.setMaxRowsPerPoll(1);
adapter.setMaxRows(1);
adapter.setRowMapper(new ItemRowMapper());
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.afterPropertiesSet();
@@ -234,7 +234,7 @@ public class JdbcPollingChannelAdapterIntegrationTests {
"select * from item where status=2");
adapter.setUpdateSql("update item set status = 10 where id = :id");
adapter.setUpdatePerRow(true);
adapter.setMaxRowsPerPoll(1);
adapter.setMaxRows(1);
adapter.setRowMapper(new ItemRowMapper());
adapter.setBeanFactory(mock(BeanFactory.class));
adapter.afterPropertiesSet();

View File

@@ -209,7 +209,7 @@ public class JdbcOutboundGatewayParserTests {
accessor = new DirectFieldAccessor(source);
source = accessor.getPropertyValue("poller"); //JdbcPollingChannelAdapter
accessor = new DirectFieldAccessor(source);
Integer maxRowsPerPoll = (Integer) accessor.getPropertyValue("maxRowsPerPoll");
Integer maxRowsPerPoll = (Integer) accessor.getPropertyValue("maxRows");
assertEquals("maxRowsPerPoll should default to 1", Integer.valueOf(1), maxRowsPerPoll);
}
@@ -225,7 +225,7 @@ public class JdbcOutboundGatewayParserTests {
accessor = new DirectFieldAccessor(source);
source = accessor.getPropertyValue("poller"); //JdbcPollingChannelAdapter
accessor = new DirectFieldAccessor(source);
Integer maxRowsPerPoll = (Integer) accessor.getPropertyValue("maxRowsPerPoll");
Integer maxRowsPerPoll = (Integer) accessor.getPropertyValue("maxRows");
assertEquals("maxRowsPerPoll should default to 10", Integer.valueOf(10), maxRowsPerPoll);
}

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:jdbc="http://www.springframework.org/schema/jdbc">
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:jdbc="http://www.springframework.org/schema/jdbc">
<int:channel id="target">
@@ -15,26 +15,28 @@
</int:channel>
<int:channel id="output">
<int:queue />
<int:queue/>
</int:channel>
<int-jdbc:outbound-gateway query="select * from bazz where id=:headers[id]" update="insert into bazz (id, status, name) values (:headers[id], 0, :payload[foo])"
request-channel="target" reply-channel="output" data-source="dataSource" auto-startup="true" max-rows-per-poll="10">
<int-jdbc:outbound-gateway query="select * from bazz where id=:headers[id]"
update="insert into bazz (id, status, name) values (:headers[id], 0, :payload[foo])"
request-channel="target" reply-channel="output" data-source="dataSource"
auto-startup="true" max-rows="10">
<int:poller fixed-rate="1000"/>
</int-jdbc:outbound-gateway>
<jdbc:embedded-database id="dataSource" type="H2"/>
<jdbc:embedded-database id="dataSource" type="H2"/>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:org/springframework/integration/jdbc/config/outboundPollerSchema.sql"/>
</jdbc:initialize-database>
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:org/springframework/integration/jdbc/config/outboundPollerSchema.sql"/>
</jdbc:initialize-database>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
<constructor-arg ref="dataSource"/>
</bean>
</beans>

View File

@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration/jdbc"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jdbc
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd">
<beans:import resource="jdbcInboundChannelAdapterCommonConfig.xml" />
<beans:import resource="jdbcInboundChannelAdapterCommonConfig.xml"/>
<inbound-channel-adapter query="select * from item where status=2"
channel="target" data-source="dataSource" max-rows-per-poll="2"
update="update item set status=10 where id in (:id)" />
channel="target" data-source="dataSource" max-rows="2"
update="update item set status=10 where id in (:id)"/>
</beans:beans>

View File

@@ -100,7 +100,7 @@ Below example provides sql type for the parameters being used in the query.
class="o.s.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="sqlParameterTypes">
<map>
<entry key="status" value=""#{ T(java.sql.Types).BINARY}" />
<entry key="status" value="#{ T(java.sql.Types).BINARY}" />
</map>
</property>
</bean>
@@ -131,14 +131,14 @@ The transaction manager configuration is not shown, but as long as it is aware o
A common use case is for the downstream channels to be direct channels (the default), so that the endpoints are invoked in the same thread, and hence the same transaction.
Then if any of them fail, the transaction rolls back and the input data is reverted to its original state.
[[jdbc-max-rows-per-poll-versus-max-messages-per-poll]]
==== Max-rows-per-poll versus Max-messages-per-poll
[[jdbc-max-rows-versus-max-messages-per-poll]]
==== Max-rows versus Max-messages-per-poll
The _JDBC Inbound Channel Adapter_ defines an attribute `max-rows-per-poll`.
The _JDBC Inbound Channel Adapter_ defines an attribute `max-rows`.
When you specify the adapter's _Poller_, you can also define a property called `max-messages-per-poll`.
While these two attributes look similar, their meaning is quite different.
`max-messages-per-poll` specifies the number of times the query is executed per polling interval, whereas `max-rows-per-poll` specifies the number of rows returned for each execution.
`max-messages-per-poll` specifies the number of times the query is executed per polling interval, whereas `max-rows` specifies the number of rows returned for each execution.
Under normal circumstances, you would likely not want to set the Poller's `max-messages-per-poll` property when using the _JDBC Inbound Channel Adapter_.
Its default value is _1_, which means that the _JDBC Inbound Channel Adapter_'s https://docs.spring.io/spring-integration/api/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.html#receive()[`receive()`] method is executed exactly once for each poll interval.
@@ -146,10 +146,13 @@ Its default value is _1_, which means that the _JDBC Inbound Channel Adapter_'s
Setting the `max-messages-per-poll` attribute to a larger value means that the query is executed that many times back to back.
For more information regarding the `max-messages-per-poll` attribute, please see <<channel-adapter-namespace-inbound>>.
In contrast, the `max-rows-per-poll` attribute, if greater than _0_, specifies the maximum number of rows that will be used from the query result set, per execution of the `receive()` method.
In contrast, the `max-rows` attribute, if greater than _0_, specifies the maximum number of rows that will be used from the query result set, per execution of the `receive()` method.
If the attribute is set to _0_, then all rows will be included in the resulting message.
If not explicitly set, the attribute defaults to _0_.
NOTE: It is recommended to use result set limiting via vendor-specific query options, for example MySQL `LIMIT` or SQL Server `TOP` or Oracle's `ROWNUM`.
See the particular vendor documentation for more information.
[[jdbc-outbound-channel-adapter]]
=== Outbound Channel Adapter
@@ -302,8 +305,8 @@ The reply message is then generated from the result, like the inbound adapter, a
[IMPORTANT]
====
By default the component for the SELECT query returns only one, first row from the cursor.
This can be adjusted with the `max-rows-per-poll` option.
Consider to specify `max-rows-per-poll="0"` if you need to return all the rows from the SELECT.
This can be adjusted with the `max-rows` option.
Consider specifying `max-rows="0"` if you need to return all the rows from the SELECT.
====
As with the channel adapters, there is also the option to provide `SqlParameterSourceFactory` instances for request and reply.
@@ -810,7 +813,7 @@ Furthermore, if you need even more control over how parameters are retrieved, co
id=""
ignore-column-meta-data="false"
is-function="false"
max-rows-per-poll="" <2>
max-rows="" <2>
skip-undeclared-results="" <3>
return-value-required="false" <4>
<int:poller/>
@@ -844,7 +847,7 @@ _Optional_.
Since _Spring Integration 3.0_. _Optional_.
NOTE: When you declare a Poller, you may notice the Poller's `max-messages-per-poll` attribute.
For information about how it relates to the `max-rows-per-poll` attribute of the _Stored Procedure Inbound Channel Adapter_, please see <<jdbc-max-rows-per-poll-versus-max-messages-per-poll>> for a thorough discussion.
For information about how it relates to the `max-rows` attribute of the _Stored Procedure Inbound Channel Adapter_, please see <<jdbc-max-rows-versus-max-messages-per-poll>> for a thorough discussion.
The meaning of the attributes is the same as for the _JDBC Inbound Channel Adapter_.
[[stored-procedure-outbound-channel-adapter]]

View File

@@ -58,3 +58,9 @@ See the note near the bottom of <<amqp-message-headers>> for more information.
The `contentType` header is no longer incorrectly mapped as an entry in the general headers map.
See <<amqp-content-type>> for more information.
==== JDBC Changes
A confusing `max-rows-per-poll` property on the JDBC Inbound Channel Adapter and JDBC Outbound Gateway has been deprecated in favor newly introduced `max-rows` property.
See <<jdbc>> for more information.