Oracle TopLink Developer's Guide
10g Release 3 (10.1.3) B13593-01 |
|
![]() Previous |
![]() Next |
When you execute a query, TopLink retrieves the information from either the database or the TopLink session cache. You can configure the way queries use the TopLink cache to optimize performance.
TopLink maintains a client-side cache to reduce the number of read operations required from the database. TopLink caches objects written to and read from the database to maintain object identity. The sequence in which a query checks the cache and database affects query performance. By default, primary key queries check the cache before accessing the database, and all queries check the cache before rebuilding an object from its row.
Note: You can override the default behavior in the caching policy configuration information in the TopLink descriptor. For more information, see "Explicit Query Refreshes" . |
This section illustrates ways to manipulate the relationship between query and cache, including the following:
The cache in a TopLink application holds objects that have already been read from or written to the database. Use of the cache in a TopLink application reduces the number of accesses to the database. Because accessing the database consumes time and resources, an effective caching strategy is important to the efficiency of your application.
For more information about configuring and using the cache, see Chapter 90, "Understanding the Cache".
An in-memory query is a query that is run against the shared session cache. Careful configuration of in-memory querying improves performance, but not all queries benefit from in-memory querying. For example, queries for individual objects based on primary keys generally see performance gains from in-memory querying; queries not based on primary keys are less likely to benefit.By default, queries that look for a single object based on primary keys attempt to retrieve the required object from the cache first, and then to search the database if the object is not in the cache. All other query types search the database first, by default. You can specify whether a given query runs against the in-memory cache, the database, or both. In-memory querying lets you perform queries on the cache rather than the database. In-memory querying supports the following relationships:
One-to-one
One-to-many
Many-to-many
Aggregate collection
Direct collection
Note: By default, the relationships themselves must be in memory for in-memory traversal to work. Ensure that you trigger all value holders to enable in-memory querying to work across relationships. |
This section describes the following:
You can configure in-memory query cache usage at the query level using ReadObjectQuery
and ReadAllQuery
methods:
checkCacheByPrimaryKey
: The default setting; if a read-object query contains an expression that compares at least the primary key, you can obtain a cache hit if you process the expression against the objects in memory.
checkCacheByExactPrimaryKey
: If a read-object query contains an expression where the primary key is the only comparison, you can obtain a cache hit if you process the expression against the object in memory.
checkCacheThenDatabase
: You can configure any read-object query to check the cache completely before you resort to accessing the database.
checkCacheOnly
: You can configure any read-all query to check only the parent session cache (not the unit of work cache) and return the result from the parent session cache without accessing the database.
conformResultsInUnitOfWork
: You can configure any read-object or read-all query within the context of a unit of work to conform the results with the changes to the object made within that unit of work. This includes new objects, deleted objects and changed objects. For more information and limitations on conforming, see "Using Conforming Queries and Descriptors".
Alternatively, you can configure cache usage using the ObjectLevelReadQuery
method setCacheUsage
, passing in the appropriate ObjectLevelReadQuery
field: CheckCacheByPrimaryKey
, CheckCacheByExactPrimaryKey
, CheckCacheThenDatabase
, CheckCacheOnly
, ConformResultsInUnitOfWork
, or DoNotCheckCache
.
You can use a subset of Expression
(see Table 96-8) and ExpressionMath
(see Table 96-9) methods with in-memory queries. For more information about these options, see "Understanding TopLink Expressions".
Table 96-8 Expressions Operator Support for In-Memory Queries
Expressions Operator | In-Memory Query Support |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Footnote 1 For more information, see "Join Reading and Object-Level Read Queries".
In-memory queries may fail for several reasons, the most common of which are the following:
The query expression is too complex to execute in memory.
There are untriggered value holders in which indirection is used. All object models that use indirection must first trigger value holders before they conform on the relevant objects.
TopLink provides a mechanism to handle indirection exceptions. To specify how the application must handle these exceptions, use the following InMemoryQueryIndirectionPolicy
methods:
throwIndirectionException
: The default setting; it is the only setting that throws indirection exceptions.
triggerIndirection
: Triggers all valueholders to eliminate the problem.
ignoreIndirectionExceptionReturnConformed
: Returns conforming if an untriggered value holder is encountered. That is, results from the database are expected to conform, and an untriggered value holder is taken to mean that the underlying attribute has not changed.
ignoreIndirectionExceptionReturnNotConformed
: Returns not conforming if an untriggered value holder is encountered.
Note: When you build new applications, consider throwing all conform exceptions. This provides more detailed feedback for unsuccessful in-memory queries. For more information, see "Exceptions During Conforming". |
When a query searches for a single object by a primary key, TopLink extracts the primary key from the query and attempts to return the object from the cache without accessing the database. If the object is not in the cache, the query executes against the database, builds the resulting object(s), and places it in the identity map.
If the query is based on a nonprimary key selection criteria or is a read-all query, the query executes against the database (unless you are using ReadObjectQuery
or ReadAllQuery
method checkCacheOnly
). The query matches primary keys from the result set to objects in the cache, and returns the cached objects, if any, in the result set.
If an object is not in the cache, TopLink builds the object. If the query is a refreshing query, TopLink updates the contents of any objects with the results from the query. Use "equals" on the object identity to properly configure and use an identity map.
Clients can refresh objects when they want to ensure that they have the latest data at a particular time.
To disable the identity map cache update, which is normally performed by a read query, call the dontMaintainCache
method. This improves the query performance when you read objects that are not needed later by the application and can avoid exceptions during partial object queries (see "Reading Objects Using Partial Object Queries").
Example 96-1 Disabling the Identity Map Cache Update
Example 96-1 demonstrates how code reads Employee
objects from the database and writes the information to a file.
// Reads objects from the employee table and writes them to an employee file void writeEmployeeTableToFile(String filename, Session session) { Vector employeeObjects; ReadAllQuery query = new ReadAllQuery(); query.setReferenceClass(Employee.class); query.setSelectionCriteria(new ExpressionBuilder.get("id").greaterThan(100)); query.dontMaintainCache(); Vector employees = (Vector) session.executeQuery(query); // Write all the employee data to a file Employee.writeToFile(filename, employees); }
You can refresh objects in the cache to ensure that they are current with the database, while preserving object identity. This section describes how to use query API to perform the following:
Configure query refreshing at the descriptor level (see "Configuring Cache Refreshing") to apply cache refreshing to all queries of a particular object type. Before configuring cache refresh options, consider their effect on performance (see "Cache Optimization").
To refresh objects in the cache with the data in the database, call the Session
method refreshObject
or the ReadObjectQuery
method setShouldRefreshIdentityMapResult(true)
.
You can control the depth at which a refreshing updates objects and their related objects. There are three options:
CascadePrivateParts: Default refresh behavior. Refreshes the local level object and objects that are referenced in privately owned, nonindirect, relationships.
CascadeNone: Refreshes only the first level of the object, but does not refresh related objects.
CascadeAll: Refreshes the entire object tree, stopping when it either reaches the leaf objects, or when it encounters untriggered indirection in the tree.
Include the refreshIdentityMapResult
method in a query to force refreshing of an identity map with the results of the query.
Example 96-2 Refreshing the Result of a Query in the Identity Map Cache During a Read Query
ReadObjectQuery query = new ReadObjectQuery(); query.setReferenceClass(Employee.class); query.setSelectionCriteria(new ExpressionBuilder().get("lastName").equal("Smith")); query.refreshIdentityMapResult(); Employee employee = (Employee) session.executeQuery(query);
The refreshIdentityMapResult
method refreshes the object's attributes, but not the attributes of its privately owned parts. However, under most circumstances, you should refresh an object's privately owned parts and other related objects to ensure consistency with the database.
To refresh privately owned or related parts, use the following methods:
cascadePrivateParts
: Refreshes all privately owned objects
cascadeAllParts
: Refreshes all related objects
Example 96-3 Using the cascadePrivateParts Method
ReadAllQuery query = new ReadAllQuery(); query.setReferenceClass(Employee.class); query.refreshIdentityMapResult(); query.cascadePrivateParts(); Vector employees = (Vector) session.executeQuery(query);
Note: If the object is in the session cache, you can also use therefreshObject method to refresh an object and its privately owned parts.
|
By default, TopLink stores query results in the session cache enabling TopLink to execute the query repeatedly, without accessing the database. This is useful when you execute queries that run against static data.
By default, a read-all query always goes to the database, as it does not know how many objects it is seeking. However if the object already exists in the cache, time can be saved by not having to build a new object from the row.
For more information, see "Understanding the Cache".
In addition to TopLink's object cache, TopLink also supports a query cache.
The object cache indexes objects by their primary key, allowing primary key queries to obtain cache hits. By using the object cache, queries that access the data source can avoid the cost of building the objects and their relationships if the object is already present.
The query cache is distinct from the object cache. The query cache is indexed by the query and the query parameters – not the object's primary key. This allows for any query executed with the same parameters to obtain a query cache hit and return the same result set.
By default, a ReadQuery
it does not cache its query result set. You can, however, configure the query to cache its result set. This is useful for frequently executed queries whose result set infrequently changes. The query cache always maintains hard references to the result set; the number of results sets for distinct parameters stored in the query cache is configurable. The query cache maintains its size number of the last executed queries with distinct parameters.
You can apply a cache invalidation policy to the query's internal cache (see "Configuring Cache Expiration at the Query Level"). For more information, see "Cache Invalidation".
TopLink does not support the use of the query cache with cursors: if you use query caching with cursors, TopLink will throw an exception. For information on cursor query results, see "Stream and Cursor Query Results" and "Handling Cursor and Stream Query Results".
TopLink caches EJB beans that EJB finders retrieve. For your application, you can configure the caching of the EJB finders' results in a variety of ways, force the cache to be refreshed, or disable the caching.
This section describes the following:
You can apply various configurations to the underlying query to achieve the correct caching behavior for the application. There are several ways to control the caching options for queries. For most queries, you can set caching options using TopLink Workbench.
You can set the caching options on a per-finder basis. Table 96-10 lists the valid values.
Table 96-10 Finder Caching Options
This Setting . . . | Causes Finders to . . . | When the Search Involves a Finder That . . . |
---|---|---|
|
Check the unit of work cache before querying the session cache or the database. The finder's results always conform to uncommitted new, deleted, and changed objects. |
Returns either a single bean or a collection. |
|
Query the database, bypassing the TopLink internal caches. |
Returns either a single bean or a collection. |
|
Check the session cache for the object. |
Contains only a primary key, and returns a single bean. |
|
Check the session cache for the object. |
Contains a primary key (and may contain other search parameters), and returns a single bean. |
|
Search the session cache before accessing the databas.e |
Returns a single bean. |
|
Search the parent session cache only (not the unit of work cache), but not the database. |
Returns either a single bean or a collection. |
Footnote 1 Default.
For more information about the TopLink queries, as well as the TopLink unit of work and how it integrates with JTS, see Chapter 100, "Understanding TopLink Transactions".
Note: To apply caching options to finders with manually created queries (findOneByQuery , findManyByQuery ), use the TopLink API.
|
By default, TopLink adds all returned objects to the session cache. However, if you know the set of returned objects is very large, and you want to avoid the expense of storing these objects, you can disable this behavior. To override the default configuration, implement the dontMaintainCache
method on the query, or disable returned object caching for the query in TopLink Workbench.
A finder may return information from the database for an object whose primary key is already in the cache. When set to true
, the Refresh Cache option (in TopLink Workbench) causes the query to refresh the object's nonprimary key attributes with the returned information. This occurs on findByPrimaryKey
finders as well as all expression and SQL finders for the bean.
If you build a query in Java code, you can set this option by including the refreshIdentityMapResult
method. This method automatically cascades changes to privately owned parts of the beans. If you require different behavior, configure the query using a dynamic finder instead.
Note: When you invoke this option from within a transaction, the refresh action overwrites object attributes, including any that have not yet been written to the database. |
If your application includes an OptimisticLock
field, use the refresh cache option in conjunction with the onlyRefreshCacheIfNewerVersion
option. This ensures that the application refreshes objects in the cache only if the version of the object in the database is newer than the version in the cache.
For finders that have no refresh cache setting, the onlyRefreshCacheIfNewerVersion
method has no effect.