Skip to content

Commit 2136b04

Browse files
committed
added limit for parsed SQL cache to NamedParameterJdbcTemplate (SPR-7237); added configurable cache limit to CachingMetadataReaderFactory
1 parent b4af04b commit 2136b04

File tree

2 files changed

+68
-19
lines changed

2 files changed

+68
-19
lines changed

org.springframework.core/src/main/java/org/springframework/core/type/classreading/CachingMetadataReaderFactory.java

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,19 @@
3434
*/
3535
public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
3636

37-
private static final int MAX_ENTRIES = 256;
37+
/** Default maximum number of entries for the MetadataReader cache: 256 */
38+
public static final int DEFAULT_CACHE_LIMIT = 256;
3839

39-
private final Map<Resource, MetadataReader> classReaderCache = createLRUCache();
40+
41+
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
42+
43+
private final Map<Resource, MetadataReader> classReaderCache =
44+
new LinkedHashMap<Resource, MetadataReader>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
45+
@Override
46+
protected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {
47+
return size() > getCacheLimit();
48+
}
49+
};
4050

4151

4252
/**
@@ -64,8 +74,27 @@ public CachingMetadataReaderFactory(ClassLoader classLoader) {
6474
}
6575

6676

77+
/**
78+
* Specify the maximum number of entries for the MetadataReader cache.
79+
* Default is 256.
80+
*/
81+
public void setCacheLimit(int cacheLimit) {
82+
this.cacheLimit = cacheLimit;
83+
}
84+
85+
/**
86+
* Return the maximum number of entries for the MetadataReader cache.
87+
*/
88+
public int getCacheLimit() {
89+
return this.cacheLimit;
90+
}
91+
92+
6793
@Override
6894
public MetadataReader getMetadataReader(Resource resource) throws IOException {
95+
if (getCacheLimit() <= 0) {
96+
return super.getMetadataReader(resource);
97+
}
6998
synchronized (this.classReaderCache) {
7099
MetadataReader metadataReader = this.classReaderCache.get(resource);
71100
if (metadataReader == null) {
@@ -76,15 +105,4 @@ public MetadataReader getMetadataReader(Resource resource) throws IOException {
76105
}
77106
}
78107

79-
80-
@SuppressWarnings("serial")
81-
private static <K, V> Map<K, V> createLRUCache() {
82-
return new LinkedHashMap<K, V>(MAX_ENTRIES, 0.75f, true) {
83-
@Override
84-
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
85-
return size() > MAX_ENTRIES;
86-
}
87-
};
88-
}
89-
90108
}

org.springframework.jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2010 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,9 @@
1616

1717
package org.springframework.jdbc.core.namedparam;
1818

19-
import java.util.HashMap;
19+
import java.util.LinkedHashMap;
2020
import java.util.List;
2121
import java.util.Map;
22-
2322
import javax.sql.DataSource;
2423

2524
import org.springframework.dao.DataAccessException;
@@ -60,11 +59,23 @@
6059
*/
6160
public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {
6261

62+
/** Default maximum number of entries for this template's SQL cache: 256 */
63+
public static final int DEFAULT_CACHE_LIMIT = 256;
64+
65+
6366
/** The JdbcTemplate we are wrapping */
6467
private final JdbcOperations classicJdbcTemplate;
6568

66-
/** Map of original SQL String to ParsedSql representation */
67-
private final Map<String, ParsedSql> parsedSqlCache = new HashMap<String, ParsedSql>();
69+
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
70+
71+
/** Cache of original SQL String to ParsedSql representation */
72+
private final Map<String, ParsedSql> parsedSqlCache =
73+
new LinkedHashMap<String, ParsedSql>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
74+
@Override
75+
protected boolean removeEldestEntry(Map.Entry<String, ParsedSql> eldest) {
76+
return size() > getCacheLimit();
77+
}
78+
};
6879

6980

7081
/**
@@ -73,7 +84,7 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
7384
* @param dataSource the JDBC DataSource to access
7485
*/
7586
public NamedParameterJdbcTemplate(DataSource dataSource) {
76-
Assert.notNull(dataSource, "The [dataSource] argument cannot be null.");
87+
Assert.notNull(dataSource, "DataSource must not be null");
7788
this.classicJdbcTemplate = new JdbcTemplate(dataSource);
7889
}
7990

@@ -96,6 +107,21 @@ public JdbcOperations getJdbcOperations() {
96107
return this.classicJdbcTemplate;
97108
}
98109

110+
/**
111+
* Specify the maximum number of entries for this template's SQL cache.
112+
* Default is 256.
113+
*/
114+
public void setCacheLimit(int cacheLimit) {
115+
this.cacheLimit = cacheLimit;
116+
}
117+
118+
/**
119+
* Return the maximum number of entries for this template's SQL cache.
120+
*/
121+
public int getCacheLimit() {
122+
return this.cacheLimit;
123+
}
124+
99125

100126
public <T> T execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback<T> action)
101127
throws DataAccessException {
@@ -294,10 +320,15 @@ protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlPa
294320

295321
/**
296322
* Obtain a parsed representation of the given SQL statement.
323+
* <p>The default implementation uses an LRU cache with an upper limit
324+
* of 256 entries.
297325
* @param sql the original SQL
298326
* @return a representation of the parsed SQL statement
299327
*/
300328
protected ParsedSql getParsedSql(String sql) {
329+
if (getCacheLimit() <= 0) {
330+
return NamedParameterUtils.parseSqlStatement(sql);
331+
}
301332
synchronized (this.parsedSqlCache) {
302333
ParsedSql parsedSql = this.parsedSqlCache.get(sql);
303334
if (parsedSql == null) {

0 commit comments

Comments
 (0)