MyBatis Cache Issues

This article explains MyBatis's first‑level and second‑level cache mechanisms, illustrates common consistency problems caused by default cache settings in both distributed and single‑session scenarios, and provides practical recommendations such as adjusting localCacheScope or deep‑copying results to avoid cache pitfalls.

政采云技术
政采云技术
政采云技术
MyBatis Cache Issues

Many Java backend services use MyBatis as their ORM framework, but developers often overlook MyBatis's caching mechanism and rely on default settings, which can lead to unexpected behavior. This article introduces the concepts of MyBatis first‑level (session) and second‑level caches and shows how to avoid common pitfalls.

Cache is essential for read‑heavy database workloads because it reduces pressure on the database and improves performance, yet improper use can cause data‑consistency issues.

First‑Level Cache

MyBatis's first‑level cache, also called the local cache, is scoped to a SqlSession and cannot be disabled; its scope can be configured via the localCacheScope property to either SESSION (default) or STATEMENT.

Problem 1

When localCacheScope is set to SESSION and the service runs multiple instances, each session caches the same record (e.g., ID 1). Updating the record in one session clears only that session's cache, while another session still returns the stale cached data, causing inconsistency.

// Session 1
SqlSession session1 = factory.openSession(true);
// Session 2
SqlSession session2 = factory.openSession(true);

TemplateInfoMapper mapper1 = session1.getMapper(TemplateInfoMapper.class);
TemplateInfoMapper mapper2 = session2.getMapper(TemplateInfoMapper.class);

TemplateInfo a1 = mapper1.get(1L);
TemplateInfo a2 = mapper2.get(1L);
Assert.assertEquals(a1.getTemplateName(), a2.getTemplateName());

a1.setTemplateName("a1");
mapper1.updateByPrimaryKey(a1);

TemplateInfo b1 = mapper1.get(1L);
TemplateInfo b2 = mapper2.get(1L);
Assert.assertEquals(b1.getTemplateName(), b2.getTemplateName()); // data inconsistency

Problem 2

Within a single session, the first query caches the result object. The second identical query returns the same object reference from the cache, so modifications to either reference affect both, making the data appear consistent even though it should not.

SqlSession session = factory.openSession(true);
TemplateInfoMapper mapper = session.getMapper(TemplateInfoMapper.class);
TemplateInfo a1 = mapper.get(1L);
a1.setTemplateName("a1");
TemplateInfo a2 = mapper.get(1L);
a2.setTemplateName("a2");
Assert.assertEquals(a1.getTemplateName(), a2.getTemplateName()); // data appears consistent
session.close();

The root cause is that each SqlSession maintains its own first‑level cache. Updating in one session clears only that session's cache, while other sessions still hold stale data. In the same session, the cache stores objects in a HashMap, returning the same reference (shallow copy), so changes to the object are reflected everywhere.

How MyBatis Executes SQL

A SqlSession creates an Executor to run SQL. The Executor contains a localCache (implemented by PerpetualCache) and first checks this cache before querying the database.

The class diagram shows that DefaultSqlSession implements SqlSession and BaseExecutor implements Executor. PerpetualCache provides a simple HashMap -based cache.

To avoid first‑level cache pitfalls, the simplest solution is to set localCacheScope to STATEMENT, which clears the cache after each query, effectively disabling the session‑level cache—recommended for distributed applications.

If only Problem 2 needs to be avoided, deep‑copying query results can prevent the shallow‑copy issue, but it is better to avoid mutating cached objects directly.

MyBatis in Spring

When used with Spring, SqlSession is bound to Spring's transaction management, and developers typically interact via Mapper interfaces or SqlSessionTemplate. The same caching principles apply.

backendJavaCacheSpringMyBatisORM
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining 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.