blob: 35a4417ea2d8cc146045c49563e9d4d222a32300 [file] [log] [blame]
Title: Caching Query Results
<P>Cayenne provides a way to cache query results, avoiding unneeded database trips for the frequently used queries. Caching strategy is configured per query. A strategy can be set via API or in CayenneModeler. Possible strategies, as defined in the <TT>org.apache.cayenne.query.QueryCacheStrategy</TT> enum are the following:</P>
<DIV class="table-wrap">
<TABLE class="confluenceTable"><TBODY>
<TR>
<TH class="confluenceTh">Policy</TH>
<TH class="confluenceTh">Cache Scope</TH>
<TH class="confluenceTh">Cache Behavior</TH>
</TR>
<TR>
<TD class="confluenceTd"><EM>(default)</EM> <TT>NO_CACHE</TT> </TD>
<TD class="confluenceTd">N/A</TD>
<TD class="confluenceTd">Always fetch, never use cache, never save to cache</TD>
</TR>
<TR>
<TD class="confluenceTd"><TT>LOCAL_CACHE</TT></TD>
<TD class="confluenceTd">ObjectContext</TD>
<TD class="confluenceTd">If result is previously cached, use it, otherwise do a fetch and store result in cache for future use</TD>
</TR>
<TR>
<TD class="confluenceTd"><TT>LOCAL_CACHE_REFRESH</TT></TD>
<TD class="confluenceTd">ObjectContext</TD>
<TD class="confluenceTd">Never use cache, always do a fetch and store result in cache for future use</TD>
</TR>
<TR>
<TD class="confluenceTd"><TT>SHARED_CACHE</TT></TD>
<TD class="confluenceTd">DataDomain (usually shared by all contexts in the same JVM)</TD>
<TD class="confluenceTd">If result is previously cached, use it, otherwise do a fetch and store result in cache for future use</TD>
</TR>
<TR>
<TD class="confluenceTd"><TT>SHARED_CACHE_REFRESH</TT></TD>
<TD class="confluenceTd">DataDomain (usually shared by all contexts in the same JVM)</TD>
<TD class="confluenceTd">Never use cache, always do a fetch and store result in cache for future use</TD>
</TR>
</TBODY></TABLE>
</DIV>
<P>It is important to understand that caching of <B>result lists</B> is done independently from caching of <B>individual DataObjects and DataRows</B>. Therefore the API is different as well. Also cached results lists are not synchronized across VMs (even the shared cache).</P>
<H3><A name="CachingQueryResults-APIforResultCaching"></A>API for Result Caching</H3>
<P>When creating queries in the code, users may set a desired cache strategy per query. Below we will create a query and set its caching policy to LOCAL_CACHE:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">
SelectQuery query = <SPAN class="code-keyword">new</SPAN> SelectQuery(Artist.class);
<SPAN class="code-comment">// set local cache strategy, meaning the cache will be stored in the ObjectContext
</SPAN><SPAN class="code-comment">// and not shared between different contexts
</SPAN>query.setCacheStrategy(QueryCacheStrategy.LOCAL_CACHE);
ObjectContext context = ... <SPAN class="code-comment">// assume <SPAN class="code-keyword">this</SPAN> exists
</SPAN>
<SPAN class="code-comment">// <SPAN class="code-keyword">if</SPAN> there was no cache at <SPAN class="code-keyword">this</SPAN> point, the query will hit the database,
</SPAN><SPAN class="code-comment">// and will store the result in the cache
</SPAN>List objects = context.performQuery(query);
</PRE>
</DIV></DIV>
<P>Now if we rerun the same query (or create a new instance of the query with the same set of parameters), we'll get cached result, which will be much faster than fetching it from DB. </P>
<BLOCKQUOTE><P>The point about 2 separate queries reusing the same cache entry is worth repeating. A cache key for each query is automatically generated by Cayenne based on the type of the query and its parameters (such as qualifier, ordering, etc.). So a query itself does not need to be cached by the user code for future reuse. New queries can be created as needed.</P></BLOCKQUOTE>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java"><SPAN class="code-comment">// creating a <SPAN class="code-keyword">new</SPAN> query, same as the previous one
</SPAN>SelectQuery query1 = <SPAN class="code-keyword">new</SPAN> SelectQuery(Artist.class);
<SPAN class="code-comment">// <SPAN class="code-keyword">this</SPAN> will hit the local cache
</SPAN>List objects1 = context.performQuery(query1);
</PRE>
</DIV></DIV>
<P>Or if we want to refresh the cache, but still keep caching the result after that:</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">query1.setCachePolicy(QueryCacheStrategy.LOCAL_CACHE_REFRESH);
List objects2 = context.performQuery(query1);
</PRE>
</DIV></DIV>
<P>The example above shows caching with <TT>SelectQuery</TT>, but it works exactly the same way for <TT>SQLTemplate</TT> and <TT>ProcedureQuery</TT>. Similarly <TT>SHARED_CACHE</TT> and <TT>SHARED_CACHE_REFRESH</TT> cache policies create cache shared by all ObjectContexts that work on top of a given DataDomain. </P>
<P>There's another optional query property called &quot;<TT>cacheGroups</TT>&quot; that allows to fine-tune cache expiration in a declarative fashion. When creating a query, a user would specify the names of the cache groups (which are really cache <EM>expiration</EM> groups) associated with this query, and then separately define expiration policies for the cache groups present in the application. See <A href="query-result-caching.html" title="Query Result Caching">Query Result Caching</A> for more details.</P>
<H3><A name="CachingQueryResults-QueriesMappedinCayenneModeler"></A>Queries Mapped in CayenneModeler</H3>
<P>Named queries created in CayenneModeler can also be configured to use caching, with the same cache strategy and cache groups parameters:</P>
<P><SPAN class="image-wrap" style=""><IMG src="caching-query-results.data/caching.jpg" style="border: 0px solid black"></SPAN></P>
<P>NamedQueries that are using caching can be executed just like any other <A href="namedquery.html" title="NamedQuery">NamedQuery</A>.</P>