Skip Headers

Oracle TopLink Developer's Guide 10g Release 3 (10.1.3) B13593-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# Queries and the Cache

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:

- Configuring the Cache

- Using In-Memory Queries

- Primary Key Queries and the Cache

- Disabling the Identity Map Cache Update During a Read Query

- Refreshing the Cache

- Caching Query Results in the Session Cache

- Caching Query Results

## Configuring the Cache

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".

## Using In-Memory Queries

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:

- Configuring Cache Usage for In-Memory Queries

- Expression Options for In-Memory Queries

- Handling Exceptions Resulting From In-Memory Queries

### Configuring Cache Usage for In-Memory Queries

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`.

### Expression Options for In-Memory Queries

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
--- | ---
`addMonths` |
`and` |
`anyof` Foot 1 |
`anyofAllowingNone` Footref 1 |
`asciiValue` |
`between` |
`concat` |
`currentDate` |
`dateToString` |
`decode` |
`equal` |
`get` Footref 1 |
`getAllowingNull` Footref 1 |
`getFunction` |
`greaterThan` |
`greaterThanEqual` |
`hexToRaw` |
`ifNull` |
`in` |
`isNull` |
`lastDay` |
`leftPad` |
`leftTrim` |
`length` |
`lessThan` |
`lessThanEqual` |
`like` |
`monthsBetween` |
`newTime` |
`nextDay` |
`notBetween` |
`notIn` |
`notIn` |
`notNull` |
`or` |
`ref` |
`replace` |
`rightPad` |
`rightTrim` |
`subQuery` |
`substring` |
`toCharacter` |
`toDate` |
`toLowerCase` |
`toNumber` |
`toUpperCase` |
`toUpperCasedWords` |
`translate` |
`trim` |
`truncateDate` |

Footnote 1 For more information, see "Join Reading and Object-Level Read Queries".

Table 96-9 ExpressionMath Operator Support for In-Memory Queries

ExpressionMath Operator | In-Memory Query Support
--- | ---
`abs` |
`acos` |
`add` |
`asin` |
`atan` |
`atan2` |
`ceil` |
`chr` |
`cos` |
`cosh` |
`exp` |
`floor` |
`ln` |
`log` |
`max` |
`min` |
`mod` |
`none` |
`power` |
`round` |
`sign` |
`sin` |
`sinh` |
`sqrt` |
`subtract` |
`tan` |
`tanh` |
`trunc` |

### Handling Exceptions Resulting From In-Memory 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".

## Primary Key Queries and the Cache

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.

## Disabling the Identity Map Cache Update During a Read Query

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);
    }

## Refreshing the Cache

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").

### Object Refresh

To refresh objects in the cache with the data in the database, call the `Session` method `refreshObject` or the `ReadObjectQuery` method `setShouldRefreshIdentityMapResult(true)`.

### Cascading Object Refresh

You can control the depth at which a refreshing updates objects and their related objects. There are three options:

1. CascadePrivateParts: Default refresh behavior. Refreshes the local level object and objects that are referenced in privately owned, nonindirect, relationships.

2. CascadeNone: Refreshes only the first level of the object, but does not refresh related objects.

3. CascadeAll: Refreshes the entire object tree, stopping when it either reaches the leaf objects, or when it encounters untriggered indirection in the tree.

### Refreshing the Identity Map Cache During a Read Query

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 the `refreshObject` method to refresh an object and its privately owned parts.

## Caching Query Results in the Session Cache

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".

## Caching Query Results

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".

### Internal Query Cache Restrictions

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".

## Caching and EJB Finders

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:

- Caching Options

- Disabling Cache for Returned Finder Results

- Refreshing Finder Results

### Caching Options

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 . . .
--- | --- | ---
`ConformResultsInUnitOfWork` Foot 1 | 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.
`DoNotCheckCache` | Query the database, bypassing the TopLink internal caches. | Returns either a single bean or a collection.
`CheckCacheByExactPrimaryKey` | Check the session cache for the object. | Contains only a primary key, and returns a single bean.
`CheckCacheByPrimaryKey` | Check the session cache for the object. | Contains a primary key (and may contain other search parameters), and returns a single bean.
`CheckCacheThenDatabase` | Search the session cache before accessing the databas.e | Returns a single bean.
`CheckCacheOnly` | 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.

### Disabling Cache for Returned Finder Results

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.

### Refreshing Finder Results

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.