MyBatis Cache Introduction, Issues, and Custom Relation Cache Implementation

This article explains MyBatis's first‑level and second‑level caching mechanisms, demonstrates data inconsistency problems caused by joined‑table queries, and provides a custom annotation‑driven relation cache solution with code examples for configuring and validating the cache behavior.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
MyBatis Cache Introduction, Issues, and Custom Relation Cache Implementation

1. MyBatis Cache Overview

MyBatis supports caching; by default only first‑level cache is enabled, second‑level cache must be configured manually.

First‑level cache is scoped to a single SqlSession (i.e., a transaction). Repeated queries of the same Mapper method within the same session return cached results unless an insert, update, or delete occurs.

Second‑level cache is application‑wide, shared across SqlSessions. When enabled, the first query result is stored in a global cache for the Mapper; subsequent identical queries retrieve data from this cache unless the Mapper performs an update.

2. Second‑level Cache Issues

When a Mapper performs a simple single‑table query, the cache works fine, but joined queries can cause stale data. For example, UserMapper joins the Organization table; updating Organization does not invalidate UserMapper’s cache, leading to inconsistent organization information.

2.1 Data Inconsistency Verification

SQL used:

SELECT u.*, o.name org_name FROM user u LEFT JOIN organization o ON u.org_id = o.id WHERE u.id = #{userId}

Mapper method: UserInfo queryUserInfo(@Param("userId") String userId); Service method:

public UserEntity queryUser(String userId) {
    UserInfo userInfo = userMapper.queryUserInfo(userId);
    return userInfo;
}

Initial query returns user with orgName "组织1". After updating organization to "组织2", the cached user still shows "组织1", demonstrating the inconsistency.

2.2 Problem‑Handling Idea

Define related Mapper2 in Mapper1 configuration.

When creating cache instance cache1 for Mapper1, read cache2 information of related Mapper2.

Store a reference to cache2 inside cache1.

When cache1 is cleared, also clear cache2.

3. Implementing Relation Cache Refresh

Enable second‑level cache using MyBatis‑Plus: mybatis-plus.configuration.cache-enabled=true Use custom annotation @CacheRelations and custom cache classes RelativeCache and RelativeCacheContext.

Annotation definition:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheRelations {
    Class<?>[] from() default {};
    Class<?>[] to() default {};
}

Key parts of RelativeCache implementation (methods putObject, getObject, clear, addRelation, loadRelations, etc.) are shown.

Cache context stores mappings between Mapper classes and their caches, as well as pending relations.

Usage example on UserMapper:

@Repository
@CacheNamespace(implementation = RelativeCache.class, eviction = RelativeCache.class, flushInterval = 30 * 60 * 1000)
@CacheRelations(from = OrganizationMapper.class)
public interface UserMapper extends BaseMapper<UserEntity> {
    UserInfo queryUserInfo(@Param("userId") String userId);
}

Corresponding XML must include

<cache-ref namespace="com.mars.system.dao.UserMapper"/>

to enable caching.

Similarly configure OrganizationMapper with the same cache implementation.

After configuration, the validation steps show that after updating the organization, the user query returns the updated organization name, confirming the relation cache works as expected.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendJavacacheMyBatisORMSecond-Level Cache
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.