Use ConcurrentLruCache (aligned with NamedParameterJdbcTemplate)
See gh-24197
This commit is contained in:
@@ -16,14 +16,10 @@
|
|||||||
|
|
||||||
package org.springframework.r2dbc.core;
|
package org.springframework.r2dbc.core;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
import org.springframework.r2dbc.core.binding.BindMarkersFactory;
|
import org.springframework.r2dbc.core.binding.BindMarkersFactory;
|
||||||
|
import org.springframework.util.ConcurrentLruCache;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +36,7 @@ import org.springframework.r2dbc.core.binding.BindMarkersFactory;
|
|||||||
* <p><b>NOTE: An instance of this class is thread-safe once configured.</b>
|
* <p><b>NOTE: An instance of this class is thread-safe once configured.</b>
|
||||||
*
|
*
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
class NamedParameterExpander {
|
class NamedParameterExpander {
|
||||||
|
|
||||||
@@ -48,68 +45,19 @@ class NamedParameterExpander {
|
|||||||
*/
|
*/
|
||||||
public static final int DEFAULT_CACHE_LIMIT = 256;
|
public static final int DEFAULT_CACHE_LIMIT = 256;
|
||||||
|
|
||||||
|
/** Cache of original SQL String to ParsedSql representation. */
|
||||||
|
private final ConcurrentLruCache<String, ParsedSql> parsedSqlCache =
|
||||||
|
new ConcurrentLruCache<>(DEFAULT_CACHE_LIMIT, NamedParameterUtils::parseSqlStatement);
|
||||||
|
|
||||||
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
|
|
||||||
|
|
||||||
private final Log logger = LogFactory.getLog(getClass());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache of original SQL String to ParsedSql representation.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
private final Map<String, ParsedSql> parsedSqlCache = new LinkedHashMap<String, ParsedSql>(
|
|
||||||
DEFAULT_CACHE_LIMIT, 0.75f, true) {
|
|
||||||
@Override
|
|
||||||
protected boolean removeEldestEntry(Map.Entry<String, ParsedSql> eldest) {
|
|
||||||
return size() > getCacheLimit();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new enabled instance of {@link NamedParameterExpander}.
|
|
||||||
*/
|
|
||||||
public NamedParameterExpander() {}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the maximum number of entries for the SQL cache. Default is 256.
|
|
||||||
*/
|
|
||||||
public void setCacheLimit(int cacheLimit) {
|
|
||||||
this.cacheLimit = cacheLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the maximum number of entries for the SQL cache.
|
|
||||||
*/
|
|
||||||
public int getCacheLimit() {
|
|
||||||
return this.cacheLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a parsed representation of the given SQL statement.
|
* Obtain a parsed representation of the given SQL statement.
|
||||||
* <p>
|
* <p>The default implementation uses an LRU cache with an upper limit of 256 entries.
|
||||||
* The default implementation uses an LRU cache with an upper limit of 256 entries.
|
|
||||||
*
|
|
||||||
* @param sql the original SQL statement
|
* @param sql the original SQL statement
|
||||||
* @return a representation of the parsed SQL statement
|
* @return a representation of the parsed SQL statement
|
||||||
*/
|
*/
|
||||||
private ParsedSql getParsedSql(String sql) {
|
private ParsedSql getParsedSql(String sql) {
|
||||||
|
return this.parsedSqlCache.get(sql);
|
||||||
if (getCacheLimit() <= 0) {
|
|
||||||
return NamedParameterUtils.parseSqlStatement(sql);
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (this.parsedSqlCache) {
|
|
||||||
|
|
||||||
ParsedSql parsedSql = this.parsedSqlCache.get(sql);
|
|
||||||
if (parsedSql == null) {
|
|
||||||
|
|
||||||
parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
|
||||||
this.parsedSqlCache.put(sql, parsedSql);
|
|
||||||
}
|
|
||||||
return parsedSql;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,11 +67,9 @@ class NamedParameterExpander {
|
|||||||
* lists may contain an array of objects, and in that case the placeholders
|
* lists may contain an array of objects, and in that case the placeholders
|
||||||
* will be grouped and enclosed with parentheses. This allows for the use of
|
* will be grouped and enclosed with parentheses. This allows for the use of
|
||||||
* "expression lists" in the SQL statement like:
|
* "expression lists" in the SQL statement like:
|
||||||
*
|
|
||||||
* <pre class="code">
|
* <pre class="code">
|
||||||
* select id, name, state from table where (name, age) in (('John', 35), ('Ann', 50))
|
* select id, name, state from table where (name, age) in (('John', 35), ('Ann', 50))
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
|
||||||
* <p>The parameter values passed in are used to determine the number of
|
* <p>The parameter values passed in are used to determine the number of
|
||||||
* placeholders to be used for a select list. Select lists should be limited
|
* placeholders to be used for a select list. Select lists should be limited
|
||||||
* to 100 or fewer elements. A larger number of elements is not guaranteed to be
|
* to 100 or fewer elements. A larger number of elements is not guaranteed to be
|
||||||
@@ -134,26 +80,17 @@ class NamedParameterExpander {
|
|||||||
* @return the expanded sql that accepts bind parameters and allows for execution
|
* @return the expanded sql that accepts bind parameters and allows for execution
|
||||||
* without further translation wrapped as {@link PreparedOperation}.
|
* without further translation wrapped as {@link PreparedOperation}.
|
||||||
*/
|
*/
|
||||||
public PreparedOperation<String> expand(String sql, BindMarkersFactory bindMarkersFactory,
|
public PreparedOperation<String> expand(
|
||||||
BindParameterSource paramSource) {
|
String sql, BindMarkersFactory bindMarkersFactory, BindParameterSource paramSource) {
|
||||||
|
|
||||||
ParsedSql parsedSql = getParsedSql(sql);
|
ParsedSql parsedSql = getParsedSql(sql);
|
||||||
|
return NamedParameterUtils.substituteNamedParameters(parsedSql, bindMarkersFactory, paramSource);
|
||||||
PreparedOperation<String> expanded = NamedParameterUtils.substituteNamedParameters(parsedSql, bindMarkersFactory,
|
|
||||||
paramSource);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("Expanding SQL statement [%s] to [%s]", sql, expanded.toQuery()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return expanded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the SQL statement and locate any placeholders or named parameters. Named parameters are returned as result of
|
* Parse the SQL statement and locate any placeholders or named parameters.
|
||||||
* this method invocation.
|
* Named parameters are returned as result of this method invocation.
|
||||||
*
|
* @return the parameter names
|
||||||
* @return the parameter names.
|
|
||||||
*/
|
*/
|
||||||
public List<String> getParameterNames(String sql) {
|
public List<String> getParameterNames(String sql) {
|
||||||
return getParsedSql(sql).getParameterNames();
|
return getParsedSql(sql).getParameterNames();
|
||||||
|
|||||||
Reference in New Issue
Block a user