From 3732032ee44009ed14dd5eca8140f57f4a56632f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sun, 25 Feb 2018 18:23:00 +0100 Subject: [PATCH] Customizable PreparedStatementCreator in NamedParameterJdbcTemplate Issue: SPR-16050 --- .../core/CallableStatementCreatorFactory.java | 3 +- .../core/PreparedStatementCreatorFactory.java | 8 +-- .../NamedParameterJdbcTemplate.java | 66 +++++++++++++------ 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java index 2a8deba73af..d0243dacc4f 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/CallableStatementCreatorFactory.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. @@ -53,6 +53,7 @@ public class CallableStatementCreatorFactory { /** * Create a new factory. Will need to add parameters via the * {@link #addParameter} method or have no parameters. + * @param callString the SQL call string */ public CallableStatementCreatorFactory(String callString) { this.callString = callString; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java index c4f485c70a4..105e4f638d4 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.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. @@ -63,6 +63,7 @@ public class PreparedStatementCreatorFactory { /** * Create a new factory. Will need to add parameters via the * {@link #addParameter} method or have no parameters. + * @param sql the SQL statement to execute */ public PreparedStatementCreatorFactory(String sql) { this.sql = sql; @@ -71,7 +72,7 @@ public class PreparedStatementCreatorFactory { /** * Create a new factory with the given SQL and JDBC types. - * @param sql SQL to execute + * @param sql the SQL statement to execute * @param types int array of JDBC types */ public PreparedStatementCreatorFactory(String sql, int... types) { @@ -81,9 +82,8 @@ public class PreparedStatementCreatorFactory { /** * Create a new factory with the given SQL and parameters. - * @param sql SQL + * @param sql the SQL statement to execute * @param declaredParameters list of {@link SqlParameter} objects - * @see SqlParameter */ public PreparedStatementCreatorFactory(String sql, List declaredParameters) { this.sql = sql; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java index ca8a402f15f..149a8806f67 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.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,6 +19,7 @@ package org.springframework.jdbc.core.namedparam; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import javax.sql.DataSource; import org.springframework.dao.DataAccessException; @@ -333,18 +334,15 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations String sql, SqlParameterSource paramSource, KeyHolder generatedKeyHolder, @Nullable String[] keyColumnNames) throws DataAccessException { - ParsedSql parsedSql = getParsedSql(sql); - String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource); - Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null); - List declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource); - PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters); - if (keyColumnNames != null) { - pscf.setGeneratedKeysColumnNames(keyColumnNames); - } - else { - pscf.setReturnGeneratedKeys(true); - } - return getJdbcOperations().update(pscf.newPreparedStatementCreator(params), generatedKeyHolder); + PreparedStatementCreator psc = getPreparedStatementCreator(sql, paramSource, pscf -> { + if (keyColumnNames != null) { + pscf.setGeneratedKeysColumnNames(keyColumnNames); + } + else { + pscf.setReturnGeneratedKeys(true); + } + }); + return getJdbcOperations().update(psc, generatedKeyHolder); } @Override @@ -358,27 +356,53 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations getParsedSql(sql), batchArgs, getJdbcOperations()); } + /** - * Build a PreparedStatementCreator based on the given SQL and named parameters. - *

Note: Not used for the {@code update} variant with generated key handling. - * @param sql SQL to execute + * Build a {@link PreparedStatementCreator} based on the given SQL and named parameters. + *

Note: Directly called from all {@code query} variants. Delegates to the common + * {@link #getPreparedStatementCreator(String, SqlParameterSource, Consumer)} method. + * @param sql the SQL statement to execute * @param paramSource container of arguments to bind - * @return the corresponding PreparedStatementCreator + * @return the corresponding {@link PreparedStatementCreator} + * @see #getPreparedStatementCreator(String, SqlParameterSource, Consumer) */ protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource paramSource) { + return getPreparedStatementCreator(sql, paramSource, null); + } + + /** + * Build a {@link PreparedStatementCreator} based on the given SQL and named parameters. + *

Note: Used for the {@code update} variant with generated key handling, and also + * delegated from {@link #getPreparedStatementCreator(String, SqlParameterSource)}. + * @param sql the SQL statement to execute + * @param paramSource container of arguments to bind + * @param customizer callback for setting further properties on the + * {@link PreparedStatementCreatorFactory} in use), applied before the + * actual {@code newPreparedStatementCreator} call + * @return the corresponding {@link PreparedStatementCreator} + * @since 5.0.5 + * @see #getParsedSql(String) + * @see PreparedStatementCreatorFactory#PreparedStatementCreatorFactory(String, List) + * @see PreparedStatementCreatorFactory#newPreparedStatementCreator(Object[]) + */ + protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource paramSource, + @Nullable Consumer customizer) { + ParsedSql parsedSql = getParsedSql(sql); String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource); - Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null); List declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource); PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters); + if (customizer != null) { + customizer.accept(pscf); + } + Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null); return pscf.newPreparedStatementCreator(params); } /** * Obtain a parsed representation of the given SQL statement. - *

The default implementation uses an LRU cache with an upper limit - * of 256 entries. - * @param sql the original SQL + *

The default implementation uses an LRU cache with an upper limit of 256 entries. + * @param sql the original SQL statement * @return a representation of the parsed SQL statement */ protected ParsedSql getParsedSql(String sql) {