| 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 "<TT>cacheGroups</TT>" 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> |