Analysis of MyBatis First-Level and Second-Level Caches and Their Configuration
This article explains MyBatis's first-level (SqlSession-scoped) and second-level (Mapper-scoped) caching mechanisms, their default behaviors, key generation, configuration options, and the impact of Spring integration, and provides recommendations for disabling caches in distributed environments to avoid data inconsistency.
In high‑concurrency environments, proper use of caching can reduce I/O and significantly improve system performance, so MyBatis provides both first‑level and second‑level caches.
MyBatis's default cache is a local cache, which may cause data consistency problems in distributed environments unless extended to a distributed cache.
First‑Level Cache Analysis: Enabled by Default and Cannot Be Disabled
The first‑level cache is based on SqlSession and is created in the BaseExecutor class; each time a SqlSession is created, a new BaseExecutor (and thus a new first‑level cache) is instantiated. SqlSession is not thread‑safe and is usually implemented with ThreadLocal for thread safety.
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSourceSource code shows that each SqlSession creation leads to a new Executor. Apart from CachingExecutor, all executors inherit from BaseExecutor, where the first‑level cache implementation resides.
The localCache stores query results, while localOutputParameterCache stores stored‑procedure results. Every BaseExecutor instance creates a new first‑level cache object.
Cache Key Generation
org.apache.ibatis.executor.BaseExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)The cache key depends on:
Mapper ID (namespace + statement ID)
Result offset and limit
SQL statement and all its parameters
Environment ID defined in the MyBatis configuration
When retrieving data, MyBatis first checks the first‑level cache; if not found, it queries the database.
Before and after each query, MyBatis decides whether to clear the first‑level cache based on the flushCache setting (default false for select statements).
flushCache Setting this to true will cause the local and second‑level caches to be flushed whenever this statement is called. Default: false for select statements. https://mybatis.org/mybatis-3/sqlmap-xml.html#select
The default localCacheScope is SESSION, meaning the cache lives for the entire SqlSession and is only cleared by DML statements.
Local cache is used by some basic functionality (association/collection mapping, circular references). The current result mapping code heavily relies on CacheKey , making it difficult to add an option to disable it. https://github.com/mybatis/mybatis-3/issues/1278
In distributed environments, set localCacheScope to STATEMENT to clear the first‑level cache on each query, avoiding stale data across nodes.
Second‑Level Cache Analysis: Global Cache, Mapper‑Scoped, Disabled by Default
The second‑level cache is a global cache shared by all SqlSession instances. It is maintained in the global Configuration object via a CachingExecutor and must be manually enabled.
Enabling Second‑Level Cache
1. In Configuration settings, set cacheEnabled to true (default is true, acting as the global switch). org.apache.ibatis.session.Configuration 2. In the Mapper XML file, add a <cache/> element to enable the cache for that Mapper.
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>When both the global switch and the Mapper <cache/> are configured, a CachingExecutor becomes effective.
org.apache.ibatis.builder.xml.XMLMapperBuilder#configurationElementSecond‑level cache queries use the same cache key as the first‑level cache.
org.apache.ibatis.executor.CachingExecutor#query(org.apache.ibatis.mapping.MappedStatement, java.lang.Object, org.apache.ibatis.session.RowBounds, org.apache.ibatis.session.ResultHandler)In a fully enabled second‑level cache scenario, select statements use the cache unless flushCache or useCache are explicitly set; insert, update, and delete statements always flush both caches.
Relationship Between First‑Level and Second‑Level Caches
First‑level cache: SqlSession‑level, enabled by default.
Second‑level cache: Mapper‑level, requires explicit enablement.
When second‑level cache is enabled, the query order is: second‑level cache → first‑level cache → database.
Impact of Spring + MyBatis on First‑Level Cache
1. In non‑transactional environments, each operation may open a new SqlSession, causing the first‑level cache to be ineffective.
2. In transactional environments, SqlSession reference counting and transaction isolation levels can lead to cache consistency issues.
org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptorConclusion
In distributed environments, it is recommended to disable both MyBatis first‑level and second‑level caches to avoid data consistency problems. Set cacheEnabled to false in the global settings to turn off the second‑level cache, and set localCacheScope to STATEMENT to clear the first‑level cache on each query.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
