Outbound update capabilities enable applications to execute SQL INSERT, UPDATE, or DELETE statements from incoming Spring Integration messages. This is useful for persisting message data to databases, logging, audit trails, and fire-and-forget database operations.
Required Dependencies:
spring-integration-jdbc (this package)spring-integration-core is requiredDataSource or JdbcOperations bean must be configuredDefault Behaviors:
keysGenerated=false (auto-generated keys not retrieved)usePayloadAsParameterSource=true (only payload used for parameters, not headers)BeanPropertySqlParameterSourceFactoryIterable/CollectionkeysGenerated=trueThreading Model:
JdbcOperations (connection pooling)Lifecycle:
Exceptions:
DataAccessException - Database access failuresMessagingException - Message handling failuresIllegalArgumentException - Invalid configurationEdge Cases:
keysGenerated=true (throws exception)Iterable, executes batch update (one PreparedStatement per element)Iterable, executes single updateusePayloadAsParameterSource=false allows access to message headers in parameter expressionsPreparedStatementSetter provides low-level control (alternative to parameter factory)package org.springframework.integration.jdbc.outbound;
public class JdbcMessageHandler extends AbstractMessageHandler {
public JdbcMessageHandler(DataSource dataSource, String updateSql);
public JdbcMessageHandler(JdbcOperations jdbcOperations, String updateSql);
public void setKeysGenerated(boolean keysGenerated);
public void setSqlParameterSourceFactory(SqlParameterSourceFactory factory);
public void setUsePayloadAsParameterSource(boolean usePayloadAsParameterSource);
public void setPreparedStatementSetter(@Nullable MessagePreparedStatementSetter setter);
public String getComponentType();
}package org.springframework.integration.jdbc.outbound;
public class StoredProcMessageHandler extends AbstractMessageHandler {
public StoredProcMessageHandler(StoredProcExecutor storedProcExecutor);
}import org.springframework.integration.jdbc.outbound.JdbcMessageHandler;
import org.springframework.integration.support.MessageBuilder;
// Basic INSERT using message payload
JdbcMessageHandler insertHandler = new JdbcMessageHandler(
dataSource,
"INSERT INTO orders (order_number, amount, status) VALUES (:orderNumber, :amount, :status)"
);
insertHandler.setUsePayloadAsParameterSource(true);
// Send message with payload as domain object
Order order = new Order("ORD-123", new BigDecimal("99.99"), "PENDING");
Message<Order> message = MessageBuilder.withPayload(order).build();
insertHandler.handleMessage(message);// UPDATE using message payload and headers
JdbcMessageHandler updateHandler = new JdbcMessageHandler(
dataSource,
"UPDATE audit_log SET message = :payload, user_id = :headers[userId], timestamp = :headers[timestamp] WHERE id = :payload.id"
);
updateHandler.setUsePayloadAsParameterSource(false); // Access both payload and headers
Message<?> auditMessage = MessageBuilder
.withPayload(new AuditEntry(123, "User logged in"))
.setHeader("userId", "user-456")
.setHeader("timestamp", System.currentTimeMillis())
.build();
updateHandler.handleMessage(auditMessage);// Batch INSERT for Iterable payload
JdbcMessageHandler batchHandler = new JdbcMessageHandler(
dataSource,
"INSERT INTO events (event_type, data) VALUES (:eventType, :data)"
);
List<Event> events = List.of(
new Event("LOGIN", "User logged in"),
new Event("LOGOUT", "User logged out"),
new Event("PURCHASE", "User made purchase")
);
Message<List<Event>> batchMessage = MessageBuilder.withPayload(events).build();
batchHandler.handleMessage(batchMessage); // Executes batch insertimport org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory;
// Using custom SqlParameterSourceFactory with SpEL expressions
ExpressionEvaluatingSqlParameterSourceFactory factory =
new ExpressionEvaluatingSqlParameterSourceFactory();
Map<String, String> expressions = Map.of(
"orderId", "payload.id",
"total", "payload.amount * payload.quantity",
"userId", "headers['user']",
"timestamp", "T(System).currentTimeMillis()"
);
factory.setParameterExpressions(expressions);
JdbcMessageHandler exprHandler = new JdbcMessageHandler(
dataSource,
"INSERT INTO order_summary (order_id, total, user_id, timestamp) VALUES (:orderId, :total, :userId, :timestamp)"
);
exprHandler.setSqlParameterSourceFactory(factory);import org.springframework.integration.jdbc.MessagePreparedStatementSetter;
// Using MessagePreparedStatementSetter for low-level control
JdbcMessageHandler psHandler = new JdbcMessageHandler(
dataSource,
"INSERT INTO events (id, type, data, created_at) VALUES (?, ?, ?, ?)"
);
psHandler.setPreparedStatementSetter((ps, message) -> {
Event event = (Event) message.getPayload();
ps.setLong(1, event.getId());
ps.setString(2, event.getType());
ps.setString(3, event.getData());
ps.setTimestamp(4, new Timestamp(message.getHeaders().getTimestamp()));
});import org.springframework.integration.jdbc.StoredProcExecutor;
import org.springframework.integration.jdbc.outbound.StoredProcMessageHandler;
import org.springframework.integration.jdbc.storedproc.ProcedureParameter;
// Configure stored procedure executor
StoredProcExecutor executor = new StoredProcExecutor(dataSource);
executor.setStoredProcedureName("LOG_ORDER_EVENT");
// Define parameters from message
List<ProcedureParameter> params = List.of(
new ProcedureParameter("order_id", null, "payload.orderId"),
new ProcedureParameter("event_type", null, "payload.eventType"),
new ProcedureParameter("user_id", null, "headers['userId']"),
new ProcedureParameter("timestamp", null, "T(System).currentTimeMillis()")
);
executor.setProcedureParameters(params);
// Create handler (ignores any return values)
StoredProcMessageHandler handler = new StoredProcMessageHandler(executor);
// Send message
Message<?> message = MessageBuilder
.withPayload(new OrderEvent(123, "CREATED"))
.setHeader("userId", "user-789")
.build();
handler.handleMessage(message);Message handlers integrate with Spring Integration channels and flows:
import org.springframework.integration.dsl.IntegrationFlow;
import static org.springframework.integration.jdbc.dsl.Jdbc.*;
@Bean
public IntegrationFlow jdbcOutboundFlow(DataSource dataSource) {
return IntegrationFlow
.from("inputChannel")
.handle(outboundAdapter(dataSource,
"INSERT INTO processed_orders (order_id, amount, processed_at) VALUES (:id, :amount, :processedAt)"))
.get();
}Or using XML configuration:
<int-jdbc:outbound-channel-adapter
channel="inputChannel"
data-source="dataSource"
query="INSERT INTO orders (order_number, amount) VALUES (:payload.orderNumber, :payload.amount)"
sql-parameter-source-factory="parameterFactory"/>Important Migration Notice:
The class org.springframework.integration.jdbc.JdbcMessageHandler 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.JdbcMessageHandler;New (Current):
import org.springframework.integration.jdbc.outbound.JdbcMessageHandler;The deprecated class is a simple wrapper that extends the new class, so migration only requires updating import statements.
:paramName syntax for named parametersusePayloadAsParameterSource=false to access message headers