Outbound gateway capabilities enable request-reply database operations where applications send request messages, execute database updates and/or queries, and receive reply messages with results. This is useful for retrieving generated keys, fetching data after updates, and complex database interactions requiring response data.
Required Dependencies:
spring-integration-jdbc (this package)spring-integration-core is requiredDataSource or JdbcOperations bean must be configuredDefault Behaviors:
maxRows=1 (default limit for SELECT queries)keysGenerated=false (auto-generated keys not retrieved by default)ColumnMapRowMapper (returns Map<String, Object>)maxRows=1List<?> when SELECT returns multiple rows or maxRows>1Map<String, Object> with generated keys when no SELECT query and keysGenerated=trueThreading Model:
JdbcOperations (connection pooling)Lifecycle:
Exceptions:
DataAccessException - Database access failuresMessagingException - Message handling failures (e.g., requiresReply=true and null result)IllegalArgumentException - Invalid configuration (e.g., null maxRows)Edge Cases:
maxRows must not be null (throws IllegalArgumentException if null):GENERATED_KEY parameterkeysGenerated=true and no SELECT query, reply payload is Map<String, Object> with keysexpectSingleResult for stored procedures extracts single result from result maprequiresReply=true throws MessagingException if reply is null or emptypackage org.springframework.integration.jdbc.outbound;
public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler {
public JdbcOutboundGateway(DataSource dataSource, String updateQuery);
public JdbcOutboundGateway(DataSource dataSource, String updateQuery, String selectQuery);
public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery);
public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery, @Nullable String selectQuery);
public void setMaxRows(Integer maxRows);
public void setKeysGenerated(boolean keysGenerated);
public void setRequestSqlParameterSourceFactory(SqlParameterSourceFactory factory);
public void setRequestPreparedStatementSetter(MessagePreparedStatementSetter setter);
public void setReplySqlParameterSourceFactory(SqlParameterSourceFactory factory);
public void setRowMapper(RowMapper<?> rowMapper);
public String getComponentType();
}package org.springframework.integration.jdbc.outbound;
public class StoredProcOutboundGateway extends AbstractReplyProducingMessageHandler {
public StoredProcOutboundGateway(StoredProcExecutor storedProcExecutor);
public void setExpectSingleResult(boolean expectSingleResult);
public void setRequiresReply(boolean requiresReply);
}import org.springframework.integration.jdbc.outbound.JdbcOutboundGateway;
import org.springframework.integration.support.MessageBuilder;
// INSERT and retrieve generated keys
JdbcOutboundGateway insertGateway = new JdbcOutboundGateway(
dataSource,
"INSERT INTO orders (order_number, amount, status) VALUES (:orderNumber, :amount, :status)"
);
insertGateway.setKeysGenerated(true);
Order newOrder = new Order("ORD-456", new BigDecimal("149.99"), "PENDING");
Message<Order> request = MessageBuilder.withPayload(newOrder).build();
Message<?> reply = (Message<?>) insertGateway.handleRequestMessage(request);
// Reply payload contains generated key(s)
Map<String, Object> keys = (Map<String, Object>) reply.getPayload();
Long generatedId = (Long) keys.get("GENERATED_KEY");// UPDATE then SELECT - update order and return updated record
JdbcOutboundGateway updateSelectGateway = new JdbcOutboundGateway(
dataSource,
"UPDATE orders SET status = :status, updated_at = CURRENT_TIMESTAMP WHERE id = :id",
"SELECT * FROM orders WHERE id = :id"
);
Map<String, Object> updateParams = Map.of(
"id", 123L,
"status", "SHIPPED"
);
Message<?> updateRequest = MessageBuilder.withPayload(updateParams).build();
Message<?> updateReply = (Message<?>) updateSelectGateway.handleRequestMessage(updateRequest);
// Reply payload contains selected order record(s)
List<Map<String, Object>> updatedOrders = (List<Map<String, Object>>) updateReply.getPayload();import org.springframework.jdbc.core.RowMapper;
JdbcOutboundGateway gatewayWithMapper = new JdbcOutboundGateway(
dataSource,
"INSERT INTO products (name, price) VALUES (:name, :price)",
"SELECT * FROM products WHERE id = :GENERATED_KEY"
);
gatewayWithMapper.setKeysGenerated(true);
gatewayWithMapper.setRowMapper((rs, rowNum) -> new Product(
rs.getLong("id"),
rs.getString("name"),
rs.getBigDecimal("price")
));
Product newProduct = new Product(null, "Widget", new BigDecimal("29.99"));
Message<Product> productRequest = MessageBuilder.withPayload(newProduct).build();
Message<?> productReply = (Message<?>) gatewayWithMapper.handleRequestMessage(productRequest);
// Reply payload is Product object from row mapper
List<Product> products = (List<Product>) productReply.getPayload();
Product insertedProduct = products.get(0);// SELECT only (no UPDATE) - query database and return results
JdbcOutboundGateway selectGateway = new JdbcOutboundGateway(
dataSource,
"SELECT 1", // Dummy update (no-op)
"SELECT * FROM orders WHERE customer_id = :payload.customerId ORDER BY created_at DESC"
);
selectGateway.setMaxRows(10);
Customer customer = new Customer(789L);
Message<Customer> selectRequest = MessageBuilder.withPayload(customer).build();
Message<?> selectReply = (Message<?>) selectGateway.handleRequestMessage(selectRequest);
List<Map<String, Object>> customerOrders = (List<Map<String, Object>>) selectReply.getPayload();import org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory;
ExpressionEvaluatingSqlParameterSourceFactory requestFactory =
new ExpressionEvaluatingSqlParameterSourceFactory();
requestFactory.setParameterExpressions(Map.of(
"orderId", "payload.id",
"newStatus", "headers['status']",
"updatedBy", "headers['userId']"
));
ExpressionEvaluatingSqlParameterSourceFactory replyFactory =
new ExpressionEvaluatingSqlParameterSourceFactory();
replyFactory.setParameterExpressions(Map.of(
"orderId", "payload.id" // Use original order ID for SELECT
));
JdbcOutboundGateway exprGateway = new JdbcOutboundGateway(
dataSource,
"UPDATE orders SET status = :newStatus, updated_by = :updatedBy WHERE id = :orderId",
"SELECT * FROM orders WHERE id = :orderId"
);
exprGateway.setRequestSqlParameterSourceFactory(requestFactory);
exprGateway.setReplySqlParameterSourceFactory(replyFactory);import org.springframework.integration.jdbc.StoredProcExecutor;
import org.springframework.integration.jdbc.outbound.StoredProcOutboundGateway;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.SqlOutParameter;
import java.sql.Types;
// Call stored procedure with IN parameters and OUT parameters
StoredProcExecutor executor = new StoredProcExecutor(dataSource);
executor.setStoredProcedureName("PROCESS_ORDER");
// Define IN and OUT parameters
List<SqlParameter> sqlParams = List.of(
new SqlParameter("order_id", Types.BIGINT),
new SqlParameter("action", Types.VARCHAR),
new SqlOutParameter("result_code", Types.INTEGER),
new SqlOutParameter("result_message", Types.VARCHAR)
);
executor.setSqlParameters(sqlParams);
// Set parameter values from message
List<ProcedureParameter> procParams = List.of(
new ProcedureParameter("order_id", null, "payload.orderId"),
new ProcedureParameter("action", null, "payload.action")
);
executor.setProcedureParameters(procParams);
// Create gateway
StoredProcOutboundGateway gateway = new StoredProcOutboundGateway(executor);
// Send request
OrderAction action = new OrderAction(123L, "SHIP");
Message<OrderAction> request = MessageBuilder.withPayload(action).build();
Message<?> reply = (Message<?>) gateway.handleRequestMessage(request);
// Reply payload is Map with OUT parameters
Map<String, Object> results = (Map<String, Object>) reply.getPayload();
Integer resultCode = (Integer) results.get("result_code");
String resultMessage = (String) results.get("result_message");// Call stored function (returns single value)
StoredProcExecutor functionExecutor = new StoredProcExecutor(dataSource);
functionExecutor.setStoredProcedureName("CALCULATE_DISCOUNT");
functionExecutor.setIsFunction(true);
functionExecutor.setReturnValueRequired(true);
List<ProcedureParameter> funcParams = List.of(
new ProcedureParameter("order_amount", null, "payload.amount"),
new ProcedureParameter("customer_tier", null, "payload.customerTier")
);
functionExecutor.setProcedureParameters(funcParams);
StoredProcOutboundGateway functionGateway = new StoredProcOutboundGateway(functionExecutor);
functionGateway.setExpectSingleResult(true); // Extract return value directly
OrderInfo orderInfo = new OrderInfo(new BigDecimal("500"), "GOLD");
Message<OrderInfo> funcRequest = MessageBuilder.withPayload(orderInfo).build();
Message<?> discountReply = (Message<?>) functionGateway.handleRequestMessage(funcRequest);
// Reply payload is the return value directly (not a Map)
BigDecimal discount = (BigDecimal) discountReply.getPayload();Gateways integrate with Spring Integration's messaging gateway pattern:
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
import static org.springframework.integration.jdbc.dsl.Jdbc.*;
@Bean
public IntegrationFlow jdbcGatewayFlow(DataSource dataSource) {
return IntegrationFlow
.from("requestChannel")
.handle(outboundGateway(dataSource,
"INSERT INTO orders (order_number, amount) VALUES (:orderNumber, :amount)",
"SELECT * FROM orders WHERE order_number = :orderNumber")
.keysGenerated(true))
.channel("replyChannel")
.get();
}
// Use with @MessagingGateway
@MessagingGateway(defaultRequestChannel = "requestChannel")
public interface OrderGateway {
List<Map<String, Object>> createOrder(Order order);
}Or using XML configuration:
<int-jdbc:outbound-gateway
request-channel="requestChannel"
reply-channel="replyChannel"
data-source="dataSource"
update="INSERT INTO orders (order_number, amount) VALUES (:payload.orderNumber, :payload.amount)"
query="SELECT * FROM orders WHERE id = :GENERATED_KEY"
keys-generated="true"
max-rows="1"/>Important Migration Notice:
The class org.springframework.integration.jdbc.JdbcOutboundGateway is deprecated since version 7.0 and marked for removal.
This class has been moved to the org.springframework.integration.jdbc.outbound package. Users should update their imports:
Old (Deprecated):
import org.springframework.integration.jdbc.JdbcOutboundGateway;New (Current):
import org.springframework.integration.jdbc.outbound.JdbcOutboundGateway;The deprecated class is a simple wrapper that extends the new class, so migration only requires updating import statements.
:GENERATED_KEY parameter