added limit for parsed SQL cache to NamedParameterJdbcTemplate (SPR-7237); added configurable cache limit to CachingMetadataReaderFactory

This commit is contained in:
Juergen Hoeller 2010-05-26 19:35:06 +00:00
parent b4af04ba9d
commit 2136b04b65
2 changed files with 68 additions and 19 deletions

View File

@ -34,9 +34,19 @@ import org.springframework.core.io.ResourceLoader;
*/ */
public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory { public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
private static final int MAX_ENTRIES = 256; /** Default maximum number of entries for the MetadataReader cache: 256 */
public static final int DEFAULT_CACHE_LIMIT = 256;
private final Map<Resource, MetadataReader> classReaderCache = createLRUCache();
private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
private final Map<Resource, MetadataReader> classReaderCache =
new LinkedHashMap<Resource, MetadataReader>(DEFAULT_CACHE_LIMIT, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<Resource, MetadataReader> eldest) {
return size() > getCacheLimit();
}
};
/** /**
@ -64,8 +74,27 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
} }
/**
* Specify the maximum number of entries for the MetadataReader cache.
* Default is 256.
*/
public void setCacheLimit(int cacheLimit) {
this.cacheLimit = cacheLimit;
}
/**
* Return the maximum number of entries for the MetadataReader cache.
*/
public int getCacheLimit() {
return this.cacheLimit;
}
@Override @Override
public MetadataReader getMetadataReader(Resource resource) throws IOException { public MetadataReader getMetadataReader(Resource resource) throws IOException {
if (getCacheLimit() <= 0) {
return super.getMetadataReader(resource);
}
synchronized (this.classReaderCache) { synchronized (this.classReaderCache) {
MetadataReader metadataReader = this.classReaderCache.get(resource); MetadataReader metadataReader = this.classReaderCache.get(resource);
if (metadataReader == null) { if (metadataReader == null) {
@ -76,15 +105,4 @@ public class CachingMetadataReaderFactory extends SimpleMetadataReaderFactory {
} }
} }
@SuppressWarnings("serial")
private static <K, V> Map<K, V> createLRUCache() {
return new LinkedHashMap<K, V>(MAX_ENTRIES, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > MAX_ENTRIES;
}
};
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2009 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,10 +16,9 @@
package org.springframework.jdbc.core.namedparam; package org.springframework.jdbc.core.namedparam;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
@ -60,11 +59,23 @@ import org.springframework.util.Assert;
*/ */
public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations { public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations {
/** Default maximum number of entries for this template's SQL cache: 256 */
public static final int DEFAULT_CACHE_LIMIT = 256;
/** The JdbcTemplate we are wrapping */ /** The JdbcTemplate we are wrapping */
private final JdbcOperations classicJdbcTemplate; private final JdbcOperations classicJdbcTemplate;
/** Map of original SQL String to ParsedSql representation */ private volatile int cacheLimit = DEFAULT_CACHE_LIMIT;
private final Map<String, ParsedSql> parsedSqlCache = new HashMap<String, ParsedSql>();
/** Cache of original SQL String to ParsedSql representation */
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();
}
};
/** /**
@ -73,7 +84,7 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
* @param dataSource the JDBC DataSource to access * @param dataSource the JDBC DataSource to access
*/ */
public NamedParameterJdbcTemplate(DataSource dataSource) { public NamedParameterJdbcTemplate(DataSource dataSource) {
Assert.notNull(dataSource, "The [dataSource] argument cannot be null."); Assert.notNull(dataSource, "DataSource must not be null");
this.classicJdbcTemplate = new JdbcTemplate(dataSource); this.classicJdbcTemplate = new JdbcTemplate(dataSource);
} }
@ -96,6 +107,21 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
return this.classicJdbcTemplate; return this.classicJdbcTemplate;
} }
/**
* Specify the maximum number of entries for this template's SQL cache.
* Default is 256.
*/
public void setCacheLimit(int cacheLimit) {
this.cacheLimit = cacheLimit;
}
/**
* Return the maximum number of entries for this template's SQL cache.
*/
public int getCacheLimit() {
return this.cacheLimit;
}
public <T> T execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback<T> action) public <T> T execute(String sql, SqlParameterSource paramSource, PreparedStatementCallback<T> action)
throws DataAccessException { throws DataAccessException {
@ -294,10 +320,15 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
/** /**
* Obtain a parsed representation of the given SQL statement. * Obtain a parsed representation of the given SQL statement.
* <p>The default implementation uses an LRU cache with an upper limit
* of 256 entries.
* @param sql the original SQL * @param sql the original SQL
* @return a representation of the parsed SQL statement * @return a representation of the parsed SQL statement
*/ */
protected ParsedSql getParsedSql(String sql) { protected ParsedSql getParsedSql(String sql) {
if (getCacheLimit() <= 0) {
return NamedParameterUtils.parseSqlStatement(sql);
}
synchronized (this.parsedSqlCache) { synchronized (this.parsedSqlCache) {
ParsedSql parsedSql = this.parsedSqlCache.get(sql); ParsedSql parsedSql = this.parsedSqlCache.get(sql);
if (parsedSql == null) { if (parsedSql == null) {