Unlock MyBatis Performance: A Deep Dive into First‑Level and Second‑Level Caching

This guide explains what caching is, why it’s essential for database‑driven applications, and how MyBatis implements first‑level and second‑level caches, including configuration steps, sample code, execution results, and key considerations to ensure effective cache usage.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Unlock MyBatis Performance: A Deep Dive into First‑Level and Second‑Level Caching

What is a cache?

A cache stores a small amount of frequently accessed data in memory, allowing faster retrieval than querying the database each time. Because server memory is limited, only critical data—such as dictionaries, system parameters, or user session information—is cached.

Why use a cache?

In a typical BS architecture most operations are read‑heavy. Repeated database queries increase load and latency. By caching query results the application queries the database once, stores the result in memory, and serves subsequent requests directly from the cache, reducing database pressure and improving response time.

MyBatis first‑level (session) cache

MyBatis enables a first‑level cache by default. All queries executed within the same SqlSession are stored in this cache. The cache is cleared when an insert, update, or delete statement runs, or when the session is closed.

Reader reader = Resources.getResourceAsReader("config/configuration.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = builder.build(reader);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
// ... perform queries ...
sqlSession.clearCache();
sqlSession.close();

Enable SQL logging to verify cache usage:

<settings>
    <!-- Standard log implementation that prints SQL -->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

Demo 1 – Simple query reuse

public static void main(String[] args) throws IOException {
    Reader reader = Resources.getResourceAsReader("config/configuration.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = builder.build(reader);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user1 = mapper.selectByPrimaryKey("3rfrf34r34"); // first DB hit
    User user2 = mapper.selectByPrimaryKey("3rfrf34r34"); // served from cache
    System.out.println("Objects equal: " + (user1 == user2));
    sqlSession.clearCache();
    sqlSession.close();
}

The console shows two SQL statements but only one actual database query, confirming that the second retrieval came from the first‑level cache.

Demo 2 – Query → Update → Query

public static void main(String[] args) throws IOException {
    // setup omitted for brevity
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.selectByPrimaryKey("3rfrf34r34"); // DB hit
    mapper.updateByPrimaryKey(user);                     // triggers cache clear
    User userAgain = mapper.selectByPrimaryKey("3rfrf34r34"); // DB hit again
    sqlSession.clearCache();
    sqlSession.close();
}

Three SQL statements appear because the update operation invalidates the cache, forcing the second query to hit the database.

MyBatis second‑level cache

The second‑level cache is global across sessions. It is populated when a session commits or closes, and subsequent sessions can read from it. Two configuration approaches exist:

Enable per‑mapper cache by adding <cache/> to the mapper XML.

Enable cache for all mappers via the global MyBatis setting cacheEnabled=true.

Per‑mapper configuration

<!-- Enable second‑level cache for this mapper -->
<cache/>

Global configuration (mybatis-config.xml)

<settings>
    <!-- Enable second‑level cache for all mappers -->
    <setting name="cacheEnabled" value="true"/>
</settings>

Second‑level cache demo

public static void main(String[] args) throws IOException {
    Reader reader = Resources.getResourceAsReader("config/configuration.xml");
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory sqlSessionFactory = builder.build(reader);

    // First session
    SqlSession session1 = sqlSessionFactory.openSession(true);
    UserMapper mapper1 = session1.getMapper(UserMapper.class);
    User u1 = mapper1.selectByPrimaryKey("3rfrf34r34"); // DB hit
    session1.clearCache();
    session1.close();

    // Second session
    SqlSession session2 = sqlSessionFactory.openSession(true);
    UserMapper mapper2 = session2.getMapper(UserMapper.class);
    User u2 = mapper2.selectByPrimaryKey("3rfrf34r34"); // Served from second‑level cache
    session2.clearCache();
    session2.close();
}

The log shows only one database query, confirming that the second session retrieved the data from the second‑level cache.

Important considerations

All select statements are cached; any insert, update, or delete will invalidate the relevant cache entries.

The cache uses an LRU (Least Recently Used) eviction policy.

Cache entries are not refreshed on a timer; they persist until evicted or invalidated.

By default the cache holds up to 1024 object references.

Cached objects are treated as read/write – callers can modify them without affecting other threads.

Understanding these mechanisms and configuring MyBatis appropriately can significantly reduce database load and improve application responsiveness.

MyBatis first‑level cache result
MyBatis first‑level cache result
MyBatis second‑level cache result
MyBatis second‑level cache result
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.

BackendJavaPerformancecacheMyBatisFirst-Level CacheSecond-Level Cache
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.