Master MyBatis Caching in Spring Boot: Complete Guide to First‑ and Second‑Level Cache
This guide explains MyBatis's two‑level caching mechanism, shows how to use the default first‑level cache and manually enable the second‑level cache in a Spring Boot project, includes code examples, test cases, third‑party Ehcache integration, and key considerations for safe deployment.
MyBatis Cache Mechanism Overview
MyBatis provides two‑level cache: first‑level (local) scoped to SqlSession, always enabled, cleared on flush/commit/close; second‑level (global) scoped to mapper namespace, disabled by default, shared across sessions, and written after session close/commit.
First‑Level Cache (Enabled by Default)
No extra configuration is required.
Example Mapper
@Mapper
public interface UserMapper {
User selectUserById(Long id);
void updateUserName(Long id, String name);
}Test Cases
@SpringBootTest
public class MybatisCacheTest {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Test
public void testFirstLevelCache() {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User u1 = mapper.selectUserById(1L); // hits DB
User u2 = mapper.selectUserById(1L); // hits cache
System.out.println(u1 == u2); // true
}
}
@Test
public void testFirstLevelCacheInvalidation() {
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
mapper.selectUserById(1L);
mapper.updateUserName(1L, "NewName"); // clears cache
mapper.selectUserById(1L); // hits DB again
}
}
}Key points: first‑level cache works only within the same SqlSession; any insert, update, or delete clears it to avoid stale data.
Second‑Level Cache (Manual Activation)
1. Enable in application.yml
mybatis:
configuration:
cache-enabled: true2. Mapper Annotation
@Mapper
@CacheNamespace // enables second‑level cache
public interface UserMapper {
User selectUserById(Long id);
}3. XML Configuration Alternative
<mapper namespace="com.example.mapper.UserMapper">
<cache/>
<select id="selectUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>4. Entity Must Implement Serializable
@Data
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String name;
private Integer age;
}5. Verify Second‑Level Cache
@Test
public void testSecondLevelCache() {
try (SqlSession s1 = sqlSessionFactory.openSession();
SqlSession s2 = sqlSessionFactory.openSession()) {
UserMapper m1 = s1.getMapper(UserMapper.class);
UserMapper m2 = s2.getMapper(UserMapper.class);
User u1 = m1.selectUserById(1L); // DB query
s1.close(); // writes to second‑level cache
User u2 = m2.selectUserById(1L); // hits cache
System.out.println(u1 == u2); // false, but data equal
}
}Second‑level cache data is stored only after session commit/close; any write operation clears the cache for the affected mapper.
Using Third‑Party Cache (Ehcache Example)
1. Add Maven Dependencies
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.9.2</version>
</dependency>2. Configure ehcache.xml
<ehcache updateCheck="false">
<diskStore path="java.io.tmpdir/ehcache"/>
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120"
overflowToDisk="false"/>
<cache name="com.example.mapper.UserMapper"
maxElementsInMemory="1000" eternal="false"
timeToIdleSeconds="300" timeToLiveSeconds="600"
overflowToDisk="false"/>
</ehcache>3. Update Mapper with Ehcache Implementation
@Mapper
@CacheNamespace(implementation = org.mybatis.caches.ehcache.EhcacheCache.class)
public interface UserMapper {
User selectUserById(Long id);
}Important Considerations
Dirty‑data risk: cache may become inconsistent when multiple mappers modify the same table.
Transactional behavior: second‑level cache becomes visible only after commit or session close.
Suitable scenarios: read‑heavy, write‑light tables (e.g., dictionaries, configuration tables); avoid for write‑heavy business tables.
Distributed environments: combine second‑level cache with external solutions like Redis for scalability.
Cache Comparison
Scope : First‑level – SqlSession; Second‑level – Mapper namespace, shared across sessions.
Default state : First‑level enabled; Second‑level disabled.
Lifecycle : First‑level cleared with SqlSession; Second‑level lives with the application.
Invalidation : First‑level on any DML or commit/close; Second‑level on DML affecting the specific mapper.
Sharing : First‑level not shareable; Second‑level shareable.
Final Summary
First‑level cache is on by default, requires no configuration, and works only within a single SqlSession.
Second‑level cache must be explicitly enabled, is suitable for read‑dominant scenarios, and persists across sessions.
For production, third‑party caches such as Ehcache or Redis are recommended to improve scalability and performance.
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.
Ray's Galactic Tech
Practice together, never alone. We cover programming languages, development tools, learning methods, and pitfall notes. We simplify complex topics, guiding you from beginner to advanced. Weekly practical content—let's grow together!
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.
