Skip to main content

Basic Concepts

Concepts

Up to now, the caches we have introduced are all single-view caches, where all clients see the same cached data.

However, often times, different clients will see different persistent data, which is usually caused by permission systems.

Since different clients will see different persistent data, we naturally also expect different clients to see different cache data, that is, the cache provides different views for different clients.

Multi-view cache solves this problem very well by allowing different clients to see different caches.

caution

Unlike previous discussions where cache can be categorized into object cache, association cache and calculated cache, multi-view cache is not adding a new category to the existing taxonomy, but rather another dimension of characteristics.

Except for object cache, both association cache and calculated cache can be combined with multi-view cache.

Single-view CacheMulti-view Cache
Object CacheObject CacheNA
Association CacheSingle-view Association CacheMulti-view Association Cache
Calculated CacheSingle-view Calculated CacheMulti-view Calculated Cache
info

We can refer to association cache and calculated cache together as property cache.

Therefore, this table can also be interpreted as property cache can be multi-viewed.

Scenarios

Multi-view cache is caused by user defined global filters.

info

As long as an entity is applied with a user defined global filter,

  • all association caches targeting it

  • calculated caches relying on these association caches

need to be multi-viewed.

For example, if an user defined global filter is added to Book, then properties like:

  • Association properties targeting Book, such as BookStore.books, Author.books

  • Calculated properties relying on the above association properties, such as BookStore.avgPrice, BookStore.newestBooks

will be sensitive to the filter, that is, different filtering conditions will result in different data seen by different clients.

caution

These filter-sensitive properties either do not support cache or support multi-view cache. Configuring single-view cache for them will be considered invalid and the cache configuration will be ignored.

Don't worry. Jimmer will tell developers why cache is abandoned.

SubKey

SubKey is an important concept for multi-view cache and a prerequisite for subsequent documentation.

Let's first take a look at the structure of single-view cache

KeyValue
Book-10{"id":10,"name":"GraphQL in Action",...}
Book.authors-1[1,2]
BookStore.avgPrice-280.333333

Here we list examples of object cache, association cache and calculated cache. Although the cache types are different, the cache structures are unified simple KV structures.

Now let's take a look at an example of multi-view cache:

KeySubKeyValue
BookStore.books-1{}[6,5,4,3,2,1,9,8,7]
{"tenant":"a"}[5,3,1,9,7]
{"tenant":"b"}[6,4,2,8]
{"module":"x"}[6,5,3,2,9,8]
{"module":"x","tenant":"a"}[5,3,9]
{"module":"x","tenant":"b"}[6,2,8]
{"module":"y"}[4,1,7]
{"module":"y","tenant":"a"}[1,7]
{"module":"y","tenant":"b"}[4]
BookStore.books-2{}[12,11,10]
{"tenant":"a"}[11]
{"tenant":"b"}[12,10]
{"module":"x"}[12,11]
{"module":"x","tenant":"a"}[11]
{"module":"x","tenant":"b"}[12]
{}[10]
{"tenant":"a"}[]
{"tenant":"b"}[10]

Multi-view cache is no longer a simple KV structure, but a nested two-level KV structure.

tip

For Redis, this structure is Redis Hashes.

In this case, the SubKey in the table is the Hash Key in Redis.

Obviously, compared to single-view cache, multi-view cache splits the data into finer granularity by sub key, allowing different clients to see different data.

  • Key

    The Key in multi-view cache is no different from the key in single-view cache, representing a specific entity property, decided by Jimmer.

  • SubKey

    The key characteristic of multi-view cache. The permission system allows different clients to have different sub keys, eventually extracting different data from the cache.

    info

    In Jimmer, SubKey must be the JSON-serialized string of java.util.SortedMap<String, Object>.

    This SortedMap must use the default sorting rule without custom Comparator.

    This is very important. For example, SubKey can only be {"module":"x","tenant":"a"}, not {tenant:"a", "module":"x"} which is different but equivalent.
    This ensures there is no redundant information internally in multi-view cache.

Multi-view cache is only for property cache, i.e. association cache and calculated cache. So association properties and complex calculated properties must specify sub key for their multi-view caches.

SubKey of Association Properties

For association properties, the necessity of multi-view cache must be caused by the associated entity being affected by user defined global filters.

Supporting multi-view cache by merely implementing the Filter/KFilter interface is not enough. The CacheableFilter/KCacheableFilter interface must be implemented.

CacheableFilter.java
package org.babyfish.jimmer.sql.filter;

public interface CacheableFilter<P extends Props> extends Filter<P> {

SortedMap<String, Object> getParameters();

...other code omitted...
}

Users need to implement the getParameters() method to contribute part of the information to sub key.

info

When multiple CacheableFilter/KCacheableFilter affect the associated entity, the data returned by the getParameters() method of each filter object is merged together as the SubKey.

SubKey of Complex Calculated Properties

Implementing complex calculated properties requires implementing the TransientResolver/KTransientResolver interface.

TransientResolver.java
package org.babyfish.jimmer.sql;

import org.babyfish.jimmer.lang.Ref;
import java.util.SortedMap;

public interface TransientResolver<ID, V> {

default Ref<SortedMap<String, Object>> getParameterMapRef() {
return Ref.empty();
}

...other code omitted...
}

This method returns the Ref which is the wrapper of SortedMap.

  • If Ref itself is null, it means getting sub key is difficult and multi-view cache cannot be applied to the calculated property.

    info

    In this case, Jimmer will tell developers why cache is abandoned.

  • Otherwise, the internal value of Ref represents the sub key of the current calculated property.

info

When invalidating cache, Jimmer will automatically delete invalid cached by key.

Cached items of multi-view cache are always deleted as a whole based on Key rather than partially based on Key + SubKey, to maximize the relative simplicity of multi-view cache.