[jOOQ/jOOQ#8334] Documented caching of ParsingConnection
This commit is contained in:
parent
8f7b51808e
commit
50825f5e1b
54
jOOQ/src/main/java/org/jooq/CacheContext.java
Normal file
54
jOOQ/src/main/java/org/jooq/CacheContext.java
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq;
|
||||
|
||||
import org.jooq.impl.CacheType;
|
||||
|
||||
/**
|
||||
* The parameter object passed to the
|
||||
* {@link CacheProvider#provide(CacheContext)} method.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface CacheContext extends Scope {
|
||||
|
||||
/**
|
||||
* The cache type for which a cache should be provided.
|
||||
*/
|
||||
CacheType cacheType();
|
||||
}
|
||||
@ -63,5 +63,5 @@ public interface CacheProvider {
|
||||
* A <code>null</code> cache effectively turns off caching for the key.
|
||||
*/
|
||||
@Nullable
|
||||
Map<Object, Object> provide(CacheType key);
|
||||
Map<Object, Object> provide(CacheContext context);
|
||||
}
|
||||
|
||||
@ -103,6 +103,7 @@ import org.jooq.exception.InvalidResultException;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.exception.NoDataFoundException;
|
||||
import org.jooq.exception.TooManyRowsException;
|
||||
import org.jooq.impl.CacheType;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.impl.ParserException;
|
||||
import org.jooq.impl.ThreadLocalTransactionProvider;
|
||||
@ -195,9 +196,23 @@ public interface DSLContext extends Scope {
|
||||
* A JDBC connection that runs each statement through the {@link #parser()}
|
||||
* first, prior to re-generating and running the SQL.
|
||||
* <p>
|
||||
* Static statements are translated eagerly upon execution, e.g. of
|
||||
* {@link java.sql.Statement#executeQuery(String)}. Prepared statements are
|
||||
* prepared lazily once all bind variables are available, because the
|
||||
* specific bind value and type may influence the generated SQL. As such, a
|
||||
* {@link PreparedStatement} created from a parsing connection does not yet
|
||||
* allocate any server side resources until it is executed for the first
|
||||
* time.
|
||||
* <p>
|
||||
* The {@link Configuration#cacheProvider()} is called for
|
||||
* {@link CacheType#CACHE_PARSING_CONNECTION} to provide a translation cache
|
||||
* to avoid the overhead of re-parsing and re-generating the same SQL string
|
||||
* all the time. By default, this is an LRU cache.
|
||||
* <p>
|
||||
* The resulting {@link Connection} wraps an underlying JDBC connection that
|
||||
* has been obtained from {@link ConnectionProvider#acquire()} and must be
|
||||
* released by calling {@link Connection#close()}.
|
||||
* released by calling {@link Connection#close()}, which calls
|
||||
* {@link ConnectionProvider#release(Connection)}.
|
||||
*/
|
||||
@NotNull
|
||||
Connection parsingConnection();
|
||||
|
||||
@ -174,6 +174,10 @@ public class Settings
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean cacheRecordMappers = true;
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean cacheParsingConnection = true;
|
||||
@XmlElement(defaultValue = "8192")
|
||||
protected Integer cacheParsingConnectionLRUCacheSize = 8192;
|
||||
@XmlElement(defaultValue = "true")
|
||||
protected Boolean cachePreparedStatementInLoader = true;
|
||||
@XmlElement(defaultValue = "THROW_ALL")
|
||||
@XmlSchemaType(name = "string")
|
||||
@ -1544,6 +1548,46 @@ public class Settings
|
||||
this.cacheRecordMappers = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether parsing connection translations should be cached in the configuration.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public Boolean isCacheParsingConnection() {
|
||||
return cacheParsingConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the cacheParsingConnection property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link Boolean }
|
||||
*
|
||||
*/
|
||||
public void setCacheParsingConnection(Boolean value) {
|
||||
this.cacheParsingConnection = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of the ParsingConnection cache's LRU cache size.
|
||||
*
|
||||
*/
|
||||
public Integer getCacheParsingConnectionLRUCacheSize() {
|
||||
return cacheParsingConnectionLRUCacheSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of the ParsingConnection cache's LRU cache size.
|
||||
*
|
||||
*/
|
||||
public void setCacheParsingConnectionLRUCacheSize(Integer value) {
|
||||
this.cacheParsingConnectionLRUCacheSize = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether JDBC {@link java.sql.PreparedStatement} instances should be cached in loader API.
|
||||
*
|
||||
@ -2986,6 +3030,20 @@ public class Settings
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withCacheParsingConnection(Boolean value) {
|
||||
setCacheParsingConnection(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation of the ParsingConnection cache's LRU cache size.
|
||||
*
|
||||
*/
|
||||
public Settings withCacheParsingConnectionLRUCacheSize(Integer value) {
|
||||
setCacheParsingConnectionLRUCacheSize(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Settings withCachePreparedStatementInLoader(Boolean value) {
|
||||
setCachePreparedStatementInLoader(value);
|
||||
return this;
|
||||
@ -3437,6 +3495,8 @@ public class Settings
|
||||
builder.append("updatablePrimaryKeys", updatablePrimaryKeys);
|
||||
builder.append("reflectionCaching", reflectionCaching);
|
||||
builder.append("cacheRecordMappers", cacheRecordMappers);
|
||||
builder.append("cacheParsingConnection", cacheParsingConnection);
|
||||
builder.append("cacheParsingConnectionLRUCacheSize", cacheParsingConnectionLRUCacheSize);
|
||||
builder.append("cachePreparedStatementInLoader", cachePreparedStatementInLoader);
|
||||
builder.append("throwExceptions", throwExceptions);
|
||||
builder.append("fetchWarnings", fetchWarnings);
|
||||
@ -4003,6 +4063,24 @@ public class Settings
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (cacheParsingConnection == null) {
|
||||
if (other.cacheParsingConnection!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!cacheParsingConnection.equals(other.cacheParsingConnection)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (cacheParsingConnectionLRUCacheSize == null) {
|
||||
if (other.cacheParsingConnectionLRUCacheSize!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!cacheParsingConnectionLRUCacheSize.equals(other.cacheParsingConnectionLRUCacheSize)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (cachePreparedStatementInLoader == null) {
|
||||
if (other.cachePreparedStatementInLoader!= null) {
|
||||
return false;
|
||||
@ -4515,6 +4593,8 @@ public class Settings
|
||||
result = ((prime*result)+((updatablePrimaryKeys == null)? 0 :updatablePrimaryKeys.hashCode()));
|
||||
result = ((prime*result)+((reflectionCaching == null)? 0 :reflectionCaching.hashCode()));
|
||||
result = ((prime*result)+((cacheRecordMappers == null)? 0 :cacheRecordMappers.hashCode()));
|
||||
result = ((prime*result)+((cacheParsingConnection == null)? 0 :cacheParsingConnection.hashCode()));
|
||||
result = ((prime*result)+((cacheParsingConnectionLRUCacheSize == null)? 0 :cacheParsingConnectionLRUCacheSize.hashCode()));
|
||||
result = ((prime*result)+((cachePreparedStatementInLoader == null)? 0 :cachePreparedStatementInLoader.hashCode()));
|
||||
result = ((prime*result)+((throwExceptions == null)? 0 :throwExceptions.hashCode()));
|
||||
result = ((prime*result)+((fetchWarnings == null)? 0 :fetchWarnings.hashCode()));
|
||||
|
||||
@ -164,12 +164,26 @@ public final class SettingsTools {
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether primary keys should be updatable.
|
||||
* Whether reflection caching is active.
|
||||
*/
|
||||
public static final boolean reflectionCaching(Settings settings) {
|
||||
return defaultIfNull(settings.isReflectionCaching(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether record mapper caching is active.
|
||||
*/
|
||||
public static final boolean recordMapperCaching(Settings settings) {
|
||||
return defaultIfNull(settings.isCacheRecordMappers(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether parsing connection caching is active.
|
||||
*/
|
||||
public static final boolean parsingConnectionCaching(Settings settings) {
|
||||
return defaultIfNull(settings.isCacheParsingConnection(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* The render locale that is applicable, or the default locale if no such
|
||||
* locale is configured.
|
||||
|
||||
@ -38,11 +38,19 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
|
||||
import static org.jooq.impl.CacheType.CacheCategory.PARSING_CONNECTION;
|
||||
import static org.jooq.impl.CacheType.CacheCategory.RECORD_MAPPER;
|
||||
import static org.jooq.impl.CacheType.CacheCategory.REFLECTION;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jooq.CacheProvider;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.DSLContext;
|
||||
import org.jooq.RecordMapper;
|
||||
import org.jooq.RecordType;
|
||||
import org.jooq.conf.Settings;
|
||||
import org.jooq.conf.SettingsTools;
|
||||
|
||||
/**
|
||||
* The set of internal cache types.
|
||||
@ -64,60 +72,74 @@ public enum CacheType {
|
||||
* A reflection cache for lookups of JPA annotated getters in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_GET_ANNOTATED_GETTER("org.jooq.configuration.reflection-cache.get-annotated-getter"),
|
||||
REFLECTION_CACHE_GET_ANNOTATED_GETTER(REFLECTION, "org.jooq.configuration.reflection-cache.get-annotated-getter"),
|
||||
|
||||
/**
|
||||
* A reflection cache for lookups of JPA annotated members in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_GET_ANNOTATED_MEMBERS("org.jooq.configuration.reflection-cache.get-annotated-members"),
|
||||
REFLECTION_CACHE_GET_ANNOTATED_MEMBERS(REFLECTION, "org.jooq.configuration.reflection-cache.get-annotated-members"),
|
||||
|
||||
/**
|
||||
* A reflection cache for lookups of JPA annotated setters in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_GET_ANNOTATED_SETTERS("org.jooq.configuration.reflection-cache.get-annotated-setters"),
|
||||
REFLECTION_CACHE_GET_ANNOTATED_SETTERS(REFLECTION, "org.jooq.configuration.reflection-cache.get-annotated-setters"),
|
||||
|
||||
/**
|
||||
* A reflection cache for lookups of getters matched by name in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_GET_MATCHING_GETTER("org.jooq.configuration.reflection-cache.get-matching-getter"),
|
||||
REFLECTION_CACHE_GET_MATCHING_GETTER(REFLECTION, "org.jooq.configuration.reflection-cache.get-matching-getter"),
|
||||
|
||||
/**
|
||||
* A reflection cache for lookups of members matched by name in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_GET_MATCHING_MEMBERS("org.jooq.configuration.reflection-cache.get-matching-members"),
|
||||
REFLECTION_CACHE_GET_MATCHING_MEMBERS(REFLECTION, "org.jooq.configuration.reflection-cache.get-matching-members"),
|
||||
|
||||
/**
|
||||
* A reflection cache for lookups of setters matched by name in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_GET_MATCHING_SETTERS("org.jooq.configuration.reflection-cache.get-matching-setters"),
|
||||
REFLECTION_CACHE_GET_MATCHING_SETTERS(REFLECTION, "org.jooq.configuration.reflection-cache.get-matching-setters"),
|
||||
|
||||
/**
|
||||
* A reflection cache to check if a type has any JPA annotations at all, in
|
||||
* {@link DefaultRecordMapper}.
|
||||
*/
|
||||
REFLECTION_CACHE_HAS_COLUMN_ANNOTATIONS("org.jooq.configuration.reflection-cache.has-column-annotations"),
|
||||
REFLECTION_CACHE_HAS_COLUMN_ANNOTATIONS(REFLECTION, "org.jooq.configuration.reflection-cache.has-column-annotations"),
|
||||
|
||||
/**
|
||||
* A cache used by the {@link DefaultRecordMapperProvider} to cache all
|
||||
* {@link RecordMapper} instances and their possibly expensive
|
||||
* initialisations per {@link RecordType} and {@link Class} pairs.
|
||||
*/
|
||||
CACHE_RECORD_MAPPERS("org.jooq.configuration.cache.record-mappers"),
|
||||
CACHE_RECORD_MAPPERS(RECORD_MAPPER, "org.jooq.configuration.cache.record-mappers"),
|
||||
|
||||
/**
|
||||
* [#8334] A cache for SQL to SQL translations in the
|
||||
* {@link DSLContext#parsingConnection()}, to speed up its usage.
|
||||
*/
|
||||
CACHE_PARSING_CONNECTION("org.jooq.configuration.cache.parsing-connection");
|
||||
CACHE_PARSING_CONNECTION(PARSING_CONNECTION, "org.jooq.configuration.cache.parsing-connection");
|
||||
|
||||
final String key;
|
||||
final CacheCategory category;
|
||||
final String key;
|
||||
|
||||
CacheType(String key) {
|
||||
CacheType(CacheCategory category, String key) {
|
||||
this.category = category;
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
enum CacheCategory {
|
||||
REFLECTION(SettingsTools::reflectionCaching),
|
||||
RECORD_MAPPER(SettingsTools::recordMapperCaching),
|
||||
PARSING_CONNECTION(SettingsTools::parsingConnectionCaching);
|
||||
|
||||
final Predicate<? super Settings> predicate;
|
||||
|
||||
CacheCategory(Predicate<? super Settings> predicate) {
|
||||
this.predicate = predicate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -407,7 +407,6 @@ import org.jooq.XMLAttributes;
|
||||
import org.jooq.XMLExistsPassingStep;
|
||||
import org.jooq.XMLQueryPassingStep;
|
||||
import org.jooq.XMLTablePassingStep;
|
||||
import org.jooq.conf.ParamType;
|
||||
import org.jooq.conf.Settings;
|
||||
import org.jooq.exception.SQLDialectNotSupportedException;
|
||||
import org.jooq.impl.XMLParse.DocumentOrContent;
|
||||
|
||||
60
jOOQ/src/main/java/org/jooq/impl/DefaultCacheContext.java
Normal file
60
jOOQ/src/main/java/org/jooq/impl/DefaultCacheContext.java
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.CacheContext;
|
||||
import org.jooq.Configuration;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class DefaultCacheContext extends AbstractScope implements CacheContext {
|
||||
|
||||
private final CacheType cacheType;
|
||||
|
||||
DefaultCacheContext(Configuration configuration, CacheType cacheType) {
|
||||
super(configuration);
|
||||
|
||||
this.cacheType = cacheType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final CacheType cacheType() {
|
||||
return cacheType;
|
||||
}
|
||||
}
|
||||
@ -38,10 +38,13 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static java.util.Collections.synchronizedMap;
|
||||
import static org.jooq.impl.Tools.settings;
|
||||
import static org.jooq.tools.StringUtils.defaultIfNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jooq.CacheContext;
|
||||
import org.jooq.CacheProvider;
|
||||
|
||||
/**
|
||||
@ -53,13 +56,13 @@ import org.jooq.CacheProvider;
|
||||
final class DefaultCacheProvider implements CacheProvider {
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> provide(CacheType key) {
|
||||
switch (key) {
|
||||
public Map<Object, Object> provide(CacheContext ctx) {
|
||||
switch (ctx.cacheType()) {
|
||||
|
||||
// TODO: Is there a better implementation than wrapping LinkedHashMap
|
||||
// in synchronizedMap(), i.e. one that does not use a monitor?
|
||||
case CACHE_PARSING_CONNECTION:
|
||||
return synchronizedMap(new LRUCache<>(1024));
|
||||
return synchronizedMap(new LRUCache<>(defaultIfNull(settings(ctx.configuration()).getCacheParsingConnectionLRUCacheSize(), 8912)));
|
||||
|
||||
default:
|
||||
return new ConcurrentHashMap<>();
|
||||
|
||||
@ -3338,7 +3338,7 @@ final class Tools {
|
||||
configuration = new DefaultConfiguration();
|
||||
|
||||
// Shortcut caching when the relevant Settings flag isn't set.
|
||||
if (!reflectionCaching(configuration.settings()))
|
||||
if (!type.category.predicate.test(configuration.settings()))
|
||||
return operation.get();
|
||||
|
||||
Object cacheOrNull = configuration.data(type);
|
||||
@ -3347,7 +3347,10 @@ final class Tools {
|
||||
cacheOrNull = configuration.data(type);
|
||||
|
||||
if (cacheOrNull == null)
|
||||
configuration.data(type, cacheOrNull = defaultIfNull(configuration.cacheProvider().provide(type), NULL));
|
||||
configuration.data(type, cacheOrNull = defaultIfNull(
|
||||
configuration.cacheProvider().provide(new DefaultCacheContext(configuration, type)),
|
||||
NULL
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -387,6 +387,14 @@ UpdatableRecord.store() and UpdatableRecord.update().]]></jxb:javadoc></jxb:prop
|
||||
<element name="cacheRecordMappers" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether record mappers should be cached in the configuration.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="cacheParsingConnection" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether parsing connection translations should be cached in the configuration.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="cacheParsingConnectionLRUCacheSize" type="int" minOccurs="0" maxOccurs="1" default="8192">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[The default implementation of the ParsingConnection cache's LRU cache size.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="cachePreparedStatementInLoader" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether JDBC {@link java.sql.PreparedStatement} instances should be cached in loader API.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user