Hibernate - 整合Ehcache二级缓存使用详解

简介: Hibernate - 整合Ehcache二级缓存使用详解

SessionFactory与Session详解博文中讲述了基于Session的一级缓存,本篇博文讲述基于SessionFactory的二级缓存。


缓存(Cache)

计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是内存。

Hibernate中提供了两个级别的缓存

  • 第一级别的缓存是 Session 级别的缓存,它是属于事务范围的缓存。这一级别的缓存由 hibernate 管理的。
  • 第二级别的缓存是 SessionFactory 级别的缓存,它是属于进程范围的缓存。

一级缓存测试如下:

  @Test
  public void testHibernateSecondLevelCache(){
    Employee employee = (Employee) session.get(Employee.class, 1);
    System.out.println(employee.getName()); 
    Employee employee2 = (Employee) session.get(Employee.class, 1);
    System.out.println(employee2.getName()); 
  }

测试结果如下:

Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
AA
AA

可以看到只发送了一次查询SQL,第一次查询后将结果放到了session的缓存中,供第二次session.get()使用。


【1】SessionFactory级别的缓存

① SessionFactory 的缓存可以分为两类:

内置缓存: Hibernate 自带的, 不可卸载。 通常在 Hibernate 的初始化阶段, Hibernate 会把映射元数据和预定义的 SQL 语句放到 SessionFactory 的缓存中, 映射元数据是映射文件中数据(hibernate.cfg.xml和*.hbm.xml 文件中的数据)的复制。 该内置缓存是只读的。

  • 外置缓存(二级缓存): 一个可配置的缓存插件。 在默认情况下, SessionFactory 不会启用这个缓存插件。外置缓存中的数据是数据库数据的复制, 外置缓存的物理介质可以是内存或硬盘。

适合放入二级缓存中的数据:

  • 很少被修改
  • 不是很重要的数据, 允许出现偶尔的并发问题

不适合放入二级缓存中的数据:

  • 经常被修改
  • 财务数据, 绝对不允许出现并发问题
  • 与其他应用程序共享的数据



② Hibernate二级缓存架构



③ 二级缓存的并发访问策略

两个并发的事务同时访问持久层的缓存的相同数据时, 也有可能出现各类并发问题。

二级缓存可以设定以下 4 种类型的并发访问策略, 每一种访问策略对应一种事务隔离级别。

  • 非严格读写(Nonstrict-read-write): 不保证缓存与数据库中数据的一致性。提供 Read Uncommited 事务隔离级别, 对于极少被修改, 而且允许脏读的数据, 可以采用这种策略。
  • 读写型(Read-write): 提供 Read Commited 数据隔离级别.对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读。
  • 事务型(Transactional): 仅在受管理环境下适用. 它提供了 Repeatable Read 事务隔离级别。对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读和不可重复读。
  • 只读型(Read-Only):提供 Serializable 数据隔离级别, 对于从来不会被修改的数据, 可以采用这种访问策略。

④ 二级缓存的提供者

Hibernate 的二级缓存是进程或集群范围内的缓存。

二级缓存是可配置的的插件, Hibernate 允许选用以下类型的缓存插件:

  • EHCache: 可作为进程范围内的缓存, 存放数据的物理介质可以使内存或硬盘, 对 Hibernate 的查询缓存提供了支持。
  • OpenSymphony OSCache:可作为进程范围内的缓存, 存放数据的物理介质可以使内存或硬盘, 提供了丰富的缓存数据过期策略, 对 Hibernate 的查询缓存提供了支持。
  • SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存。
  • JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存。

4 种缓存插件支持的并发访问策略(√ 代表支持, 空白代表不支持)

image.png


【2】二级缓存配置与使用

① 配置进程范围内的二级缓存的步骤:

  • 选择合适的缓存插件: EHCache(jar 包和 配置文件), 并编辑配置文件;
  <!-- hibernate+ehcache -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-ehcache</artifactId>
         <version>${hibernate.version}</version>
    </dependency>
    <!-- EHcache -->
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>${ehcache.version}</version>
    </dependency>
  • 在 Hibernate 的配置文件(hibernate.cfg.xml)中启用二级缓存并指定和 EHCache 对应的缓存适配器;
<!-- 启用二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 配置使用的二级缓存的产品 -->
<property name="hibernate.cache.region.factory_class">
  org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>

选择需要使用二级缓存的持久化类, 设置它的二级缓存的并发访问策略

  • <class>元素的 cache 子元素表明 Hibernate 会缓存对象的简单属性, 但不会缓存集合属性, 若希望缓存集合属性中的元素, 必须在<set> 元素中加入 <cache>子元素;
  • 在 hibernate 配置文件(hibernate.cfg.xml)中通过 <class-cache/><collection-cache节点配置使用缓存。

Department.hbm.xml如下:

<hibernate-mapping package="com.jane.model">
    <class name="Department" table="GG_DEPARTMENT">
      <cache usage="read-write"/>
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <set name="emps" table="GG_EMPLOYEE" inverse="true" lazy="true">
            <key>
                <column name="DEPT_ID" />
            </key>
            <one-to-many class="Employee" />
<!--             <cache usage="read-write"/> -->
        </set>
    </class>
</hibernate-mapping>

hibernate.cfg.xml配置如下:

<class-cache usage="read-write" class="com.jane.model.Employee"/>
<class-cache usage="read-write" class="com.jane.model.Department"/>
<collection-cache usage="read-write" collection="com.jane.model.Department.emps"/>

② 测试简单属性代码如下:

  @Test
  public void testHibernateSecondLevelCache(){
    Employee employee = (Employee) session.get(Employee.class, 1);
    System.out.println(employee.getName()); 
    transaction.commit();
    session.close();
    session = sessionFactory.openSession();
    transaction = session.beginTransaction();
    Employee employee2 = (Employee) session.get(Employee.class, 1);
    System.out.println(employee2.getName()); 
  }

测试结果如下:

Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
AA
AA

③ 测试集合属性

默认情况下,集合属性不会被缓存,如下所示:

  @Test
  public void testCollectionSecondLevelCache(){
    Department dept = (Department) session.get(Department.class, 1);
    System.out.println(dept.getName());
    System.out.println(dept.getEmps().size()); 
    transaction.commit();
    session.close();
    session = sessionFactory.openSession();
    transaction = session.beginTransaction();
    Department dept2 = (Department) session.get(Department.class, 1);
    System.out.println(dept2.getName());
    System.out.println(dept2.getEmps().size()); 
  }

结果如下:

Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2

每次需要使用对象的集合属性时,都需要发送SQL语句进行查询。

如果需要缓存集合属性,则有两个解决办法:

  • <set> 元素中加入 <cache>子元素;
 <set name="emps" table="GG_EMPLOYEE" inverse="true" lazy="true">
   <key>
        <column name="DEPT_ID" />
    </key>
    <one-to-many class="Employee" />
     <cache usage="read-write"/> 
</set>
  • 在hibernate.cfg.xml中添加元素。
<collection-cache usage="read-write" collection="com.jane.model.Department.emps"/>

再次测试结果如下:

Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2
AA
2

只查询一次Department和其关联的Employees。需要注意的是集合属性缓存使用时,不光要缓存集合属性,而且还要缓存集合里面的对象。

如下所示,不缓存集合里面的对象:

<!-- 二级缓存作用的持久化类 -->
<!--    <class-cache usage="read-write" class="com.jane.model.Employee"/> -->
    <class-cache usage="read-write" class="com.jane.model.Department"/>
    <collection-cache usage="read-write" collection="com.jane.model.Department.emps"/>

再次测试结果如下:

Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2
AA
Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
2

这种情况下,实际效果更差了。


【3】ehcache.xml详解

① 实例如下

<ehcache>
    <!-- Sets the path to the directory where cache .data files are created.
         If the path is a Java System Property it is replaced by
         its value in the running VM.
         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <!--  
      指定一个目录:当 EHCache 需要把数据写到硬盘上时, 将把数据写到这个目录下.
    -->     
    <diskStore path="d:\\tempDirectory"/>
<!--Default Cache configuration. These will applied to caches programmatically created 
    through   the CacheManager.
The following attributes are required for defaultCache:
maxInMemory       - Sets the maximum number of objects that will be created in memory
eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element   is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
              if the element is not eternal. Idle time is now - last accessed time
timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
              if the element is not eternal. TTL is now - creation time
overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
              has reached the maxInMemory limit.
-->
    <!--  
      设置缓存的默认数据过期策略 
    -->    
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />
    <cache name="com.jane.model.Employee"
        maxElementsInMemory="1"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
    <cache name="com.jane.model.Department.emps"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        />
</ehcache>

② 详细说明如下

<diskStore>: 指定一个目录:当 EHCache 需要把数据写到硬盘上时, 将把数据写到这个目录下。

<defaultCache>: 设置缓存的默认数据过期策略 。

<cache>设定具体的命名缓存的数据过期策略,每个命名缓存代表一个缓存区域。

缓存区域(region):一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略。如果没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略。即:<defaultCache.../>

Hibernate 在不同的缓存区域保存不同的类/集合:

  • 对于类而言,区域的名称是类名。如:com.jane.model.Customer
  • 对于集合而言,区域的名称是类名加属性名。如com.jane.model.Customer.orders

defaultCache属性详解解释如下:

  • name: 设置缓存的名字,它的取值为类的全限定名或类的集合的名字 。
  • maxElementsInMemory: 设置基于内存的缓存中可存放的对象最大数目。
  • eternal: 设置对象是否为永久的, true表示永不过期。此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false
  • timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。
  • timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值 。
  • overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中

【4】Query 接口的 iterate() 方法

Query 接口的 iterator() 方法说明如下:

  • 同 list() 一样也能执行查询操作;
  • list() 方法执行的 SQL 语句包含实体类对应的数据表的所有字段;
  • Iterator() 方法执行的SQL 语句中仅包含实体类对应的数据表的 ID 字段。

当遍历访问结果集时, 该方法先到 Session 缓存及二级缓存中查看是否存在特定 OID 的对象, 如果存在, 就直接返回该对象, 如果不存在该对象就通过相应的 SQL Select 语句到数据库中加载特定的实体对象

大多数情况下, 应考虑使用 list() 方法执行查询操作. iterator() 方法仅在满足以下条件的场合, 可以稍微提高查询性能:

  • 要查询的数据表中包含大量字段
  • 启用了二级缓存, 且二级缓存中可能已经包含了待查询的对象

测试代码一query.list():

  @Test
  public void testQueryIterate(){
    Department dept = (Department) session.get(Department.class, 1);
    System.out.println(dept.getName());
    System.out.println(dept.getEmps().size()); 
    Query query = session.createQuery("FROM Employee e WHERE e.dept.id = 1");
    //list方法查询出来一系列Employee对象并封装为list<employee>
    List<Employee> emps = query.list();
    System.out.println(emps.size()); 
  }

查询结果如下:

Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2
Hibernate: 
    select
        employee0_.ID as ID1_1_,
        employee0_.NAME as NAME2_1_,
        employee0_.SALARY as SALARY3_1_,
        employee0_.EMAIL as EMAIL4_1_,
        employee0_.DEPT_ID as DEPT_ID5_1_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.DEPT_ID=1
2

测试代码二query.iterate()方法

  @Test
  public void testQueryIterate(){
    Department dept = (Department) session.get(Department.class, 1);
    System.out.println(dept.getName());
    System.out.println(dept.getEmps().size()); 
    Query query = session.createQuery("FROM Employee e WHERE e.dept.id = 1");
//    List<Employee> emps = query.list();
//    System.out.println(emps.size()); 
    //将OID查询出来
    Iterator<Employee> empIt = query.iterate();
    while(empIt.hasNext()){
      System.out.println(empIt.next().getName()); 
    }
  }

注意,测试二是在测试一的基础上进行的测试,此时query.list()的结果在二级缓存中。

测试二结果如下:

Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2
Hibernate: 
    select
        employee0_.ID as col_0_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.DEPT_ID=1
AA
BB

可以看到,在测试一的基础上进行的测试二,性能比测试一稍微提高(只查询了OID,根据OID去缓存里面找对应对象,不用再向内存中添加一批Employee对象)。


测试三,不在测试一的基础上,如下所示:

  @Test
  public void testQueryIterate(){
    Department dept = (Department) session.get(Department.class, 1);
    System.out.println(dept.getName());
    System.out.println(dept.getEmps().size()); 
    //这里修改了部门id与上面不同
    Query query = session.createQuery("FROM Employee e WHERE e.dept.id = 2");
//    List<Employee> emps = query.list();
//    System.out.println(emps.size()); 
    Iterator<Employee> empIt = query.iterate();
    while(empIt.hasNext()){
      System.out.println(empIt.next().getName()); 
    }
  }

测试结果如下:

Hibernate: 
    select
        department0_.ID as ID1_0_0_,
        department0_.NAME as NAME2_0_0_ 
    from
        GG_DEPARTMENT department0_ 
    where
        department0_.ID=?
AA
Hibernate: 
    select
        emps0_.DEPT_ID as DEPT_ID5_1_0_,
        emps0_.ID as ID1_1_0_,
        emps0_.ID as ID1_1_1_,
        emps0_.NAME as NAME2_1_1_,
        emps0_.SALARY as SALARY3_1_1_,
        emps0_.EMAIL as EMAIL4_1_1_,
        emps0_.DEPT_ID as DEPT_ID5_1_1_ 
    from
        GG_EMPLOYEE emps0_ 
    where
        emps0_.DEPT_ID=?
2
Hibernate: 
    select
        employee0_.ID as col_0_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.DEPT_ID=2
Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
CC
Hibernate: 
    select
        employee0_.ID as ID1_1_0_,
        employee0_.NAME as NAME2_1_0_,
        employee0_.SALARY as SALARY3_1_0_,
        employee0_.EMAIL as EMAIL4_1_0_,
        employee0_.DEPT_ID as DEPT_ID5_1_0_ 
    from
        GG_EMPLOYEE employee0_ 
    where
        employee0_.ID=?
DD

iterate()方法将OID查询出来,在需要的时候根据OID去数据库查询对象出来,性能降低!


目录
相关文章
|
3月前
|
缓存 NoSQL Java
揭秘性能提升的超级武器:掌握Hibernate二级缓存策略!
【9月更文挑战第3天】在软件开发中,性能优化至关重要。使用Hibernate进行数据持久化的应用可通过二级缓存提升数据访问速度。一级缓存随Session生命周期变化,而二级缓存是SessionFactory级别的全局缓存,能显著减少数据库访问次数,提高性能。要启用二级缓存,需在映射文件或实体类上添加相应配置。然而,并非所有场景都适合使用二级缓存,需根据业务需求和数据变更频率决定。此外,还可与EhCache、Redis等第三方缓存集成,进一步增强缓存效果。合理运用二级缓存策略,有助于大幅提升应用性能。
102 5
|
4月前
|
缓存 Java 数据库连接
Hibernate 中的查询缓存是什么?
【8月更文挑战第21天】
43 0
|
4月前
|
存储 缓存 Java
|
4月前
|
存储 缓存 Java
Hibernate 中默认启用二级缓存吗?
【8月更文挑战第21天】
39 0
|
4月前
|
存储 缓存 Java
Hibernate 中的二级缓存是什么?
【8月更文挑战第21天】
46 0
|
4月前
|
缓存 Java 数据库连接
Hibernate 中的一级缓存是什么?
【8月更文挑战第21天】
55 0
|
6月前
|
存储 缓存 监控
SpringBoot配置第三方专业缓存技术Ehcache
SpringBoot配置第三方专业缓存技术Ehcache
52 1
|
6月前
|
缓存 监控 负载均衡
Java一分钟之-Ehcache:分布式缓存系统
【6月更文挑战第17天】**Ehcache是Java的开源缓存库,支持本地和分布式缓存,提供负载均衡、数据复制和容错能力。常见问题包括网络分区导致的数据不一致、缓存雪崩和配置不当引起的性能瓶颈。解决策略涉及选择强一致性策略、设置合理缓存过期时间和监控调整配置。使用Ehcache需添加相关依赖,并配置分布式缓存,如示例所示,通过CacheManager创建和管理缓存。实践中,持续监控和优化配置至关重要。**
153 1
|
6月前
|
缓存 Java
修改缓存供应商--EhCache
修改缓存供应商--EhCache
|
7月前
|
缓存 Java 数据库连接
hibernate二级缓存
在配置和使用Hibernate二级缓存时,你应该根据应用的需求和性能要求,合理选择缓存提供者和配置参数,以达到性能优化的目的。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
68 1