首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Ehcache 與 MyBatis 整合實戰:從配置到驗證的完整指南

     編輯:Java 綜合教學

前言

Ehcache 是成熟的 Java 進程內緩存框架,支持堆內/堆外/磁盤三級存儲,與 MyBatis 無縫整合可大幅降低數據庫查詢壓力。本文通過完整實戰演示,從依賴引入、配置文件編寫、實體類序列化、Mapper 配置到效果驗證,構建「開箱即用」的二級緩存方案。

一、環境準備與依賴

Maven 依賴

<dependencies>
    <!-- MyBatis 核心 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    
    <!-- MyBatis-Ehcache 整合包 -->
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.1.0</version>
    </dependency>
    
    <!-- Ehcache 核心 (由 mybatis-ehcache 傳遞引入) -->
</dependencies>

二、核心配置文件

1. ehcache.xml - 緩存策略配置

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd">
    
    <!-- 默認緩存策略 -->
    <defaultCache 
        maxElementsInMemory="10000" 
        eternal="false" 
        timeToIdleSeconds="300" 
        timeToLiveSeconds="600" 
        overflowToDisk="true" 
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU" />
    
    <!-- 磁盤存儲路徑 (生產環境請修改為持久化目錄) -->
    <diskStore path="D:/cache" />  <!-- Windows 開發環境 -->
    <!--  -->  <!-- Linux 生產環境 -->
    
</ehcache>

關鍵屬性解析:

屬性含義建議值
maxElementsInMemory內存最大對象數根據業務量級設置,如 10000-100000
eternal是否永不過期(true 時忽略 TTL/TTI)false(需配合 TTL/TTI)
timeToIdleSeconds (TTI)最大閒置時間,超過則過期300-600 秒
timeToLiveSeconds (TTL)最大生存時間,超過則過期600-1800 秒
overflowToDisk內存不足時是否溢寫磁盤true(需配置 diskStore)
memoryStoreEvictionPolicy淘汰策略:LRU/LFU/FIFOLRU(最近最少使用)

2. 實體類序列化(關鍵)

public class User implements Serializable {
    private static final long serialVersionUID = 1L; // 必須顯式聲明,避免反序列化失敗
    
    private Long id;
    private String username;
    private String email;
    // getter/setter/toString...
}

核心要求:

  • 實現 java.io.Serializable 接口
  • 顯式聲明 serialVersionUID(禁止依賴 IDE 自動生成,跨 JVM 部署會不一致)
  • 所有嵌套對象亦需序列化

3. Mapper.xml 啟用二級緩存

<mapper namespace="com.example.mapper.UserMapper">
    
    <!-- 方式一:標準 Ehcache 實現(推薦) -->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache" />
    
    <!-- 方式二:帶日志輸出(調試用) -->
    <!--  -->
    
    <select id="selectById" resultType="User" useCache="true">
        SELECT * FROM users WHERE id = #{id}
    </select>
    
    <select id="selectAll" resultType="User" useCache="true">
        SELECT * FROM users
    </select>
    
    <!-- 寫操作自動觸發緩存刷新 -->
    <insert id="insert" parameterType="User" flushCache="true">
        INSERT INTO users(username, email) VALUES(#{username}, #{email})
    </insert>
    
    <update id="update" parameterType="User" flushCache="true">
        UPDATE users SET username=#{username}, email=#{email} WHERE id=#{id}
    </update>
    
    <delete id="deleteById" parameterType="Long" flushCache="true">
        DELETE FROM users WHERE id = #{id}
    </delete>
    
</mapper>

關鍵配置點:

  • type="org.mybatis.caches.ehcache.EhcacheCache":指定緩存實現類
  • useCache="true":查詢語句啟用緩存(默認 true,可顯式關閉)
  • flushCache="true":增刪改語句執行後刷新緩存(默認 true)

三、效果驗證

1. 測試代碼

@Test
public void testEhcache() {
    SqlSession session1 = sqlSessionFactory.openSession();
    SqlSession session2 = sqlSessionFactory.openSession(); // 不同 Session 模擬不同請求
    
    UserMapper mapper1 = session1.getMapper(UserMapper.class);
    UserMapper mapper2 = session2.getMapper(UserMapper.class);
    
    // 第一次查詢 - 觸發 SQL
    User user1 = mapper1.selectById(1L);
    System.out.println("第一次查詢: " + user1);
    session1.close(); // 關鍵:MyBatis 二級緩存需提交/關閉 Session 才寫入
    
    // 第二次查詢 - 命中緩存
    User user2 = mapper2.selectById(1L);
    System.out.println("第二次查詢: " + user2);
    session2.close();
    
    // 驗證緩存命中
    Assert.assertSame(user1, user2); // 同一緩存對象引用
}

2. 控制台輸出對比

==>  Preparing: SELECT * FROM users WHERE id = ?
==> Parameters: 1(Long)
<==    Columns: id, username, email
<==        Row: 1, zhangsan, zhangsan@example.com
第一次查詢: User(id=1, username=zhangsan, email=zhangsan@example.com)

第二次查詢: User(id=1, username=zhangsan, email=zhangsan@example.com)

3. 磁盤緩存文件驗證

配置 overflowToDisk="true" 後,查看 D:/cache 目錄:

D:\cache
├── com.example.mapper.UserMapper.data  (緩存數據文件)
├── com.example.mapper.UserMapper.index (緩存索引文件)
└── ehcache.lock                        (鎖文件)

四、進階配置與最佳實踐

1. 針對不同表定制緩存策略

<!-- ehcache.xml 中添加命名緩存 -->
<cache name="com.example.mapper.UserMapper"
       maxElementsInMemory="5000"
       timeToIdleSeconds="180"
       timeToLiveSeconds="300"
       overflowToDisk="true"
       eternal="false"
       memoryStoreEvictionPolicy="LRU" />

<cache name="com.example.mapper.OrderMapper"
       maxElementsInMemory="20000"
       timeToIdleSeconds="60"
       timeToLiveSeconds="120"
       overflowToDisk="false"
       eternal="false"
       memoryStoreEvictionPolicy="LFU" />

Mapper 中引用:<cache-ref namespace="com.example.mapper.UserMapper" />

2. 緩存關鍵監控指標

// 程序化獲取統計信息
CacheManager cacheManager = CacheManager.getInstance();
Ehcache cache = cacheManager.getEhcache("com.example.mapper.UserMapper");

System.out.println("命中率: " + cache.getStatistics().getCacheHitPercentage() + "%");
System.out.println("內存命中: " + cache.getStatistics().getInMemoryHits());
System.out.println("磁盤命中: " + cache.getStatistics().getOnDiskHits());
System.out.println("未命中: " + cache.getStatistics().getCacheMisses());
System.out.println("當前大小: " + cache.getSize() + " / " + cache.getMaxElementsInMemory());

3. 生產環境避坑指南

  • 序列化版本一致性:集群部署時確保所有節點實體類 serialVersionUID 完全一致
  • 緩存穿透防護:對不存在的 Key 緩存空對象(new User()),設置較短 TTL
  • 緩存雪崩預防:TTL 增加隨機因子(如 timeToLiveSeconds="300 + random(60)"),避免大量 Key 同時過期
  • 事務一致性:MyBatis 二級緩存非事務型,高一致性場景建議用 Redis + 分布式鎖或 Canal 監聽 Binlog 失效
  • 內存溢出防護:設置合理 maxElementsInMemory,啟用 overflowToDisk,監控 Ehcache 統計指標

五、結語

Ehcache + MyBatis 整合僅需「一個依賴、一個配置文件、一行 Mapper 配置、實體類序列化」四步即可落地。通過合理的緩存策略(TTL/TTI/淘汰算法/磁盤溢寫)、監控指標觀測、生產環境避坑指南,可構建高可用、高性能的二級緩存層,將數據庫 QPS 壓力降低 80% 以上。建議團隊建立「緩存設計規範」,新表上線必填緩存策略文檔,將緩存治理從事後補救轉為事前設計。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved