SQL mapping framework that eliminates JDBC boilerplate and couples objects with stored procedures or SQL statements using XML descriptors or annotations.
—
Multi-level caching system with configurable eviction policies and decorators for performance optimization. MyBatis provides session-level (L1) and global (L2) caching with extensive customization options.
Core caching interface that all cache implementations must implement.
/**
* Basic cache interface for storing and retrieving objects
*/
interface Cache {
/** Get cache identifier */
String getId();
/** Store object in cache */
void putObject(Object key, Object value);
/** Retrieve object from cache */
Object getObject(Object key);
/** Remove object from cache */
Object removeObject(Object key);
/** Clear all cached objects */
void clear();
/** Get current cache size */
int getSize();
}Basic HashMap-based cache implementation that serves as the foundation for all cache decorators.
/**
* Basic HashMap-based cache implementation
*/
class PerpetualCache implements Cache {
/** Create cache with specified ID */
public PerpetualCache(String id);
/** Get cache ID */
public String getId();
/** Get current cache size */
public int getSize();
/** Store object in cache */
public void putObject(Object key, Object value);
/** Retrieve object from cache */
public Object getObject(Object key);
/** Remove specific object from cache */
public Object removeObject(Object key);
/** Clear all cached objects */
public void clear();
}MyBatis uses the decorator pattern to add functionality to basic cache implementations.
Least Recently Used eviction policy that removes the least recently accessed items when cache reaches size limit.
/**
* LRU (Least Recently Used) eviction policy cache decorator
*/
class LruCache implements Cache {
/** Create LRU cache wrapping another cache implementation */
public LruCache(Cache delegate);
/** Set maximum cache size (default: 1024) */
public void setSize(int size);
}First In, First Out eviction policy that removes the oldest items when cache reaches size limit.
/**
* FIFO (First In, First Out) eviction policy cache decorator
*/
class FifoCache implements Cache {
/** Create FIFO cache wrapping another cache implementation */
public FifoCache(Cache delegate);
/** Set maximum cache size (default: 1024) */
public void setSize(int size);
}Uses Java's SoftReference for automatic memory-based eviction when memory is low.
/**
* Soft reference based cache for automatic memory-based eviction
*/
class SoftCache implements Cache {
/** Create soft reference cache wrapping another cache */
public SoftCache(Cache delegate);
}Uses Java's WeakReference for automatic garbage collection-based eviction.
/**
* Weak reference based cache for automatic GC-based eviction
*/
class WeakCache implements Cache {
/** Create weak reference cache wrapping another cache */
public WeakCache(Cache delegate);
}Automatically clears cache at specified intervals.
/**
* Time-based cache clearing decorator
*/
class ScheduledCache implements Cache {
/** Create scheduled cache with flush interval */
public ScheduledCache(Cache delegate);
/** Set flush interval in milliseconds */
public void setClearInterval(long clearInterval);
/** Get flush interval */
public long getClearInterval();
}Thread-safe cache wrapper using synchronization.
/**
* Thread-safe cache wrapper using synchronization
*/
class SynchronizedCache implements Cache {
/** Create synchronized cache wrapping another cache */
public SynchronizedCache(Cache delegate);
}Prevents cache stampede by blocking concurrent access to the same key during cache miss.
/**
* Blocking cache to prevent cache stampede
*/
class BlockingCache implements Cache {
/** Create blocking cache wrapping another cache */
public BlockingCache(Cache delegate);
/** Set timeout for blocking operations */
public void setTimeout(long timeout);
}Stores cached objects in serialized form to reduce memory usage.
/**
* Serialization-based cache storage decorator
*/
class SerializedCache implements Cache {
/** Create serialized cache wrapping another cache */
public SerializedCache(Cache delegate);
}Adds logging capabilities to cache operations for debugging and monitoring.
/**
* Cache decorator with logging capabilities
*/
class LoggingCache implements Cache {
/** Create logging cache wrapping another cache */
public LoggingCache(Cache delegate);
/** Get cache hit ratio */
public double getHitRatio();
/** Get total requests count */
public long getRequestCount();
/** Get cache hits count */
public long getHitCount();
}Provides transaction-aware caching with rollback support.
/**
* Transaction-aware cache with rollback support
*/
class TransactionalCache implements Cache {
/** Create transactional cache wrapping another cache */
public TransactionalCache(Cache delegate);
/** Commit pending cache operations */
public void commit();
/** Rollback pending cache operations */
public void rollback();
/** Clear pending operations */
public void clear();
}<!-- Global cache settings in mybatis-config.xml -->
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="localCacheScope" value="SESSION"/>
</settings>
</configuration>
<!-- Mapper-level cache configuration -->
<mapper namespace="com.example.UserMapper">
<cache
type="org.apache.ibatis.cache.impl.PerpetualCache"
eviction="LRU"
flushInterval="60000"
size="512"
readOnly="false"
blocking="true"/>
<select id="findById" resultType="User" useCache="true">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>/**
* Cache namespace configuration annotation
*/
@interface CacheNamespace {
/** Cache implementation class */
Class<? extends Cache> implementation() default PerpetualCache.class;
/** Eviction policy class */
Class<? extends Cache> eviction() default LruCache.class;
/** Flush interval in milliseconds (0 = no automatic flushing) */
long flushInterval() default 0;
/** Maximum number of cached objects */
int size() default 1024;
/** Read/write cache (true) or read-only cache (false) */
boolean readWrite() default true;
/** Use blocking cache to prevent cache stampede */
boolean blocking() default false;
/** Additional cache properties */
Property[] properties() default {};
}
/**
* Cache namespace reference annotation
*/
@interface CacheNamespaceRef {
/** Referenced mapper class */
Class<?> value() default void.class;
/** Referenced namespace name */
String name() default "";
}
/**
* Cache property configuration
*/
@interface Property {
/** Property name */
String name();
/** Property value */
String value();
}Usage Examples:
@CacheNamespace(
implementation = PerpetualCache.class,
eviction = LruCache.class,
flushInterval = 300000, // 5 minutes
size = 1024,
readWrite = true,
blocking = true,
properties = {
@Property(name = "compression", value = "true"),
@Property(name = "serialization", value = "java")
}
)
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{id}")
@Options(useCache = true)
User findById(@Param("id") Long id);
@Select("SELECT * FROM users WHERE status = #{status}")
@Options(useCache = true, flushCache = false)
List<User> findByStatus(@Param("status") String status);
@Update("UPDATE users SET name = #{name} WHERE id = #{id}")
@Options(flushCache = true)
int updateName(@Param("id") Long id, @Param("name") String name);
}
// Reference cache from another mapper
@CacheNamespaceRef(UserMapper.class)
public interface UserProfileMapper {
@Select("SELECT * FROM user_profiles WHERE user_id = #{userId}")
UserProfile findByUserId(@Param("userId") Long userId);
}Creating custom cache implementations for specialized requirements.
public class RedisCacheImpl implements Cache {
private final String id;
private final RedisTemplate<String, Object> redisTemplate;
private final String keyPrefix;
public RedisCacheImpl(String id) {
this.id = id;
this.redisTemplate = ApplicationContextHolder.getBean(RedisTemplate.class);
this.keyPrefix = "mybatis:cache:" + id + ":";
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object key, Object value) {
String redisKey = keyPrefix + key.toString();
redisTemplate.opsForValue().set(redisKey, value, Duration.ofMinutes(30));
}
@Override
public Object getObject(Object key) {
String redisKey = keyPrefix + key.toString();
return redisTemplate.opsForValue().get(redisKey);
}
@Override
public Object removeObject(Object key) {
String redisKey = keyPrefix + key.toString();
Object value = redisTemplate.opsForValue().get(redisKey);
redisTemplate.delete(redisKey);
return value;
}
@Override
public void clear() {
Set<String> keys = redisTemplate.keys(keyPrefix + "*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
@Override
public int getSize() {
Set<String> keys = redisTemplate.keys(keyPrefix + "*");
return keys != null ? keys.size() : 0;
}
}
// Usage with annotation
@CacheNamespace(implementation = RedisCacheImpl.class)
public interface ProductMapper {
@Select("SELECT * FROM products WHERE id = #{id}")
Product findById(@Param("id") Long id);
}Understanding how MyBatis generates cache keys for proper cache behavior.
/**
* Cache key generation and management
*/
class CacheKey implements Cloneable, Serializable {
/** Create new cache key */
public CacheKey();
/** Create cache key with base components */
public CacheKey(Object[] objects);
/** Update cache key with additional component */
public void update(Object object);
/** Update cache key with all components from list */
public void updateAll(Object[] objects);
/** Clone this cache key */
public CacheKey clone() throws CloneNotSupportedException;
}Monitoring cache performance and hit rates.
// Cache statistics example
@CacheNamespace(
implementation = PerpetualCache.class,
eviction = LruCache.class,
size = 1000
)
public interface OrderMapper {
@Select("SELECT * FROM orders WHERE id = #{id}")
@Options(useCache = true)
Order findById(@Param("id") Long id);
}
// Monitoring cache performance
public class CacheMonitor {
public void printCacheStats(Configuration configuration) {
Collection<Cache> caches = configuration.getCaches();
for (Cache cache : caches) {
if (cache instanceof LoggingCache) {
LoggingCache loggingCache = (LoggingCache) cache;
System.out.println("Cache: " + cache.getId());
System.out.println("Hit Ratio: " + loggingCache.getHitRatio());
System.out.println("Total Requests: " + loggingCache.getRequestCount());
System.out.println("Cache Hits: " + loggingCache.getHitCount());
}
}
}
}/**
* Local cache scope options
*/
enum LocalCacheScope {
/** Cache scoped to SqlSession (default) */
SESSION,
/** Cache scoped to individual statements */
STATEMENT
}
/**
* Cache-related exceptions
*/
class CacheException extends PersistenceException {
public CacheException(String message);
public CacheException(String message, Throwable cause);
}
/**
* Cache statistics interface
*/
interface CacheStats {
/** Get cache hit count */
long getHitCount();
/** Get cache miss count */
long getMissCount();
/** Get total request count */
long getRequestCount();
/** Get hit ratio (hits / total requests) */
double getHitRatio();
/** Reset statistics */
void reset();
}Install with Tessl CLI
npx tessl i tessl/maven-org-mybatis--mybatis