From 32030c3233e6cf37bc5b0550b600e40cae29dd16 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 14 Jun 2018 17:53:25 -0400 Subject: [PATCH] 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 --- .../integration/jdbc/JdbcOutboundGateway.java | 98 ++++++++------ .../jdbc/JdbcPollingChannelAdapter.java | 123 ++++++++++-------- .../config/JdbcOutboundGatewayParser.java | 30 +++-- .../JdbcPollingChannelAdapterParser.java | 35 +++-- .../config/spring-integration-jdbc-5.1.xsd | 27 +++- .../jdbc/JdbcOutboundGatewayTests.java | 13 +- ...PollingChannelAdapterIntegrationTests.java | 6 +- .../JdbcOutboundGatewayParserTests.java | 4 +- ...OutboundGatewayWithPoller2Test-context.xml | 28 ++-- ...thMaxRowsJdbcInboundChannelAdapterTest.xml | 12 +- src/reference/asciidoc/jdbc.adoc | 23 ++-- src/reference/asciidoc/whats-new.adoc | 6 + 12 files changed, 247 insertions(+), 158 deletions(-) diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java index f8bddc006a..bd0476b0f3 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java @@ -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); - } - } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java index aa92ca51bf..210f519497 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java @@ -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 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> resultSetExtractor; - - if (this.maxRowsPerPoll > 0) { - resultSetExtractor = rs -> { - List results = new ArrayList(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> temp = - new RowMapperResultSetExtractor((RowMapper) 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"; - } - } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java index 2148c28dc9..6ba9343af4 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java @@ -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"; } + } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java index 3d4e26757c..426cffd2c0 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParser.java @@ -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(); } diff --git a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-5.1.xsd b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-5.1.xsd index 8743d80e24..1abf4db82a 100644 --- a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-5.1.xsd +++ b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-5.1.xsd @@ -174,9 +174,17 @@ - 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'. + + + + + + + Limits the number of rows extracted per query. + Otherwise all rows are extracted into the outgoing message. @@ -360,13 +368,24 @@ + + + [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'. + + + + 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. diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java index 2b31d0247a..70fa8152bb 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcOutboundGatewayTests.java @@ -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()); } } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapterIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapterIntegrationTests.java index 3396a4e16c..a098da2dfa 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapterIntegrationTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapterIntegrationTests.java @@ -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(); diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java index 6481b3a445..f5bd9ccbc2 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java @@ -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); } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayWithPoller2Test-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayWithPoller2Test-context.xml index fb8490ee0f..a13706a016 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayWithPoller2Test-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayWithPoller2Test-context.xml @@ -1,13 +1,13 @@ + 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"> @@ -15,26 +15,28 @@ - + - + - + - - - + + + - + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithMaxRowsJdbcInboundChannelAdapterTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithMaxRowsJdbcInboundChannelAdapterTest.xml index dcd23111fa..e2252295e1 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithMaxRowsJdbcInboundChannelAdapterTest.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithMaxRowsJdbcInboundChannelAdapterTest.xml @@ -1,17 +1,17 @@ - + + channel="target" data-source="dataSource" max-rows="2" + update="update item set status=10 where id in (:id)"/> diff --git a/src/reference/asciidoc/jdbc.adoc b/src/reference/asciidoc/jdbc.adoc index e0bd706f32..e7087adb64 100644 --- a/src/reference/asciidoc/jdbc.adoc +++ b/src/reference/asciidoc/jdbc.adoc @@ -100,7 +100,7 @@ Below example provides sql type for the parameters being used in the query. class="o.s.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory"> - + @@ -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 <>. -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> @@ -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 <> for a thorough discussion. +For information about how it relates to the `max-rows` attribute of the _Stored Procedure Inbound Channel Adapter_, please see <> for a thorough discussion. The meaning of the attributes is the same as for the _JDBC Inbound Channel Adapter_. [[stored-procedure-outbound-channel-adapter]] diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc index fb09e0f043..d4805b80b3 100644 --- a/src/reference/asciidoc/whats-new.adoc +++ b/src/reference/asciidoc/whats-new.adoc @@ -58,3 +58,9 @@ See the note near the bottom of <> for more information. The `contentType` header is no longer incorrectly mapped as an entry in the general headers map. See <> 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 <> for more information.