专栏首页生活不止眼前的代码SpringBoot 2.0.4 使用Ehcache作为Hibernate的二级缓存和系统缓存

SpringBoot 2.0.4 使用Ehcache作为Hibernate的二级缓存和系统缓存

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/yingziisme/article/details/81436355

本文基于springboot 2.0.4 使用ehcache作为Hibernate的二级缓存 以及系统缓存 额外需要用的是mysql数据库

由于springboot2.x和1.x差别较大 使用1.x可能会有错误 另外ehcache版本也会导致有不同的问题 本文默认使用了spring-boot-starter-cache里面的ehcache

首先 先看一下POM文件的配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.demo.mt</groupId>
<artifactId>ehcache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>ehcache</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<!-- 数据库动态条件查询 -->
<dependency>
<groupId>com.github.wenhao</groupId>
<artifactId>jpa-spec</artifactId>
<version>3.1.1</version>
</dependency>
<!-- 集成ehcache需要的依赖-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>


</project>

使用的时候遇到一个错误是

Caused by: net.sf.ehcache.CacheException: Another CacheManager with same name 'HIBERNATE_CACHE' already exists in the same VM. Please provide unique names for each CacheManager in the config or do one of following:
1. Use one of the CacheManager.create() static factory methods to reuse same CacheManager with same name or create one if necessary
2. Shutdown the earlier cacheManager before creating new one with same name.

这里是由于Ehcache新版本只能有一个CacheManager导致,新增一个ehcache配置文件提供给系统缓存 这里本来是新增了一个ehcache配置给hibernate 但是hibernate的配置项provider_configuration_file_resource_path似乎无效 可能是路径写的有问题 最终是修改了系统缓存文件路径解决了报错

这里是application.yml

spring:
  application:
    name: ehcache-demo
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/ehcachedb?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true
    username: root
    password: 123456
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimum-idle: 1
      maximum-pool-size: 100
      auto-commit: true
      idle-timeout: 30000
      pool-name: AdvZuulHikariCP
      max-lifetime: 1800000
      connection-timeout: 30000
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    properties:
      hibernate:
        format-sql: true
        cache:
          use_query_cache: true
          use_second_level_cache: true
          provider_configuration_file_resource_path: ehcache.xml
          region:
            factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
      javax:
        persistence:
          sharedCache:
            mode: ENABLE_SELECTIVE
  cache:
    type: ehcache
    ehcache:
      config: classpath:ehcache/ehcache-spring.xml
server:
  port: 10001

hibernate使用的ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>

<ehcache name="HIBERNATE_CACHE" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">

    <!--
      指定二级缓存存放在磁盘上的位置,可以使用磁盘目录,也可以使用Java System Property目录,user.home是用户目录、user.dir是用户当前工作目录、java.io.tmpdir是默认临时文件路径
      -->
    <diskStore path="../cache/hibernate"/>


    <transactionManagerLookup class="net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup"
                              properties="jndiName=java:/TransactionManager" propertySeparator=";"/>




    <defaultCache
            maxEntriesLocalHeap="0"
            eternal="false"
            timeToIdleSeconds="1200"
            timeToLiveSeconds="1200">
        <!--<terracotta/>-->
    </defaultCache>
    <!--可以给每个实体类指定一个配置文件,通过name属性指定,要使用类的全名
        1. name:Cache的唯一标识。
        2. maxElementsInMemory:内存中最大缓存对象数。
        3. eternal:Element是否永久有效,一旦设置true,timeout将不起作用。
        4. timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
        5. timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
        6. overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
        7. maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
        8. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理缓存中的内容。默认策略是LRU(最近最少使用),你也可以设置为FIFO(先进先出)或是LFU(较少使用)

        9. diskSpoolBufferSizeMB  : 这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
        10. maxEntriesLocalHeap堆内存中最大缓存对象数,0没有限制(必须设置)
        11. maxEntriesLocalDisk硬盘最大缓存个数

    -->
    <cache name="entityCache"
           maxEntriesLocalHeap="1000"
           maxEntriesLocalDisk="10000"
           eternal="false"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="10"
           timeToLiveSeconds="20"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
        <persistence strategy="localTempSwap"/>

    </cache>

    <cache name="org.hibernate.cache.internal.StandardQueryCache"
           maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
        <persistence strategy="localTempSwap"/>

    </cache>

    <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
           maxEntriesLocalHeap="5000" eternal="true">
        <persistence strategy="localTempSwap"/>

    </cache>

</ehcache>

系统使用的ehcache-spring.xml

<?xml version="1.0" encoding="UTF-8"?>

<ehcache name="DEFAULT_CACHE" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd"
         updateCheck="true" monitoring="autodetect"
         dynamicConfig="true">


    <diskStore path="../cache/default"/>

    <defaultCache
            maxEntriesLocalHeap="0"
            eternal="false"
            timeToIdleSeconds="1200"
            timeToLiveSeconds="1200">
        <!--<terracotta/>-->
    </defaultCache>


    <cache name="testCache"
           maxEntriesLocalHeap="1000"
           maxEntriesLocalDisk="10000"
           eternal="false"
           diskSpoolBufferSizeMB="20"
           timeToIdleSeconds="20"
           timeToLiveSeconds="20"
           memoryStoreEvictionPolicy="LFU"
           transactionalMode="off">
        <persistence strategy="localTempSwap"/>
        <cacheEventListenerFactory class="com.demo.mt.ehcache.config.ehcache.CustomerCacheEventListenerFactory"/>
    </cache>

</ehcache>

其中

<cacheEventListenerFactory class="com.demo.mt.ehcache.config.ehcache.CustomerCacheEventListenerFactory"/>

这一部分是可以不要的 自己实例化一个监听器可以方便做一些统计或者一些其他处理

首先是关于Hibernate的二级缓存

在主类上添加缓存注解@EnableCaching

@EnableCaching
@SpringBootApplication
public class EhcacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(EhcacheApplication.class, args);
    }


}

在实体上加注解

@Data
@Entity
@Table(name = "role_tb")
@EqualsAndHashCode(callSuper = false)
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "entityCache")
public class RoleEntity extends BaseEntity<RoleEntity, Long> {

    protected String roleName;
}

这样就完成了hibernate的二级缓存配置 使用测试工具请求 GET http://localhost:10001/role/1 就可以测试缓存的效果了

前面用hibernate的二级缓存只能用于findById这类的请求 对于findAll则无效 不知道有没有其他什么配置

后来又使用了系统缓存 在controller层加了注解测试

package com.demo.mt.ehcache.controller;

import com.alibaba.fastjson.JSONObject;
import com.demo.mt.ehcache.entity.BaseEntity;
import com.demo.mt.ehcache.service.BaseService;
import com.demo.mt.ehcache.utils.ResultModel;
import com.github.wenhao.jpa.Specifications;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.MessageSource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;

/**
 * BaseController
 *
 * @author MT.LUO
 * 2018/7/9 11:34
 * @Description:
 */
@Slf4j
@CacheConfig(cacheNames = "testCache")
public class BaseController<S extends BaseService<T, ID>, T extends BaseEntity<T, ID>, ID extends Serializable> {
    @Autowired
    protected S baseManager;

    @Autowired
    private MessageSource messageSource;

    @Cacheable(key = "#root.target + '_' + #p0 + '_' + #p1")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public ResultModel getList(@RequestParam int pageSize, @RequestParam int pageNumber) {
        log.info("BaseController list");
        Specification<T> specification = Specifications.<T>and().eq("deleted", false).build();

        if (pageSize > 0) {

            Pageable pageable = PageRequest.of(pageNumber, pageSize);
            Page<T> page = baseManager.findAll(specification, pageable);
            return ResultModel.ok(page);

        } else if (pageSize == -1) {
            return ResultModel.ok(baseManager.findAll());
        } else {
            List<T> entities = baseManager.findAll(specification);
            return ResultModel.ok(entities);
        }
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResultModel findOne(@PathVariable ID id) {
        return ResultModel.ok(baseManager.findOne(id));
    }
}

通过请求 GET http://localhost:10001/user/list?pageSize=10&pageNumber=0 可以测试缓存效果

这里贴出源码地址GITHUB

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • solidity智能合约字节数最大值及缩减字节数

    在Solidity中,EIP 170将contract的最大大小限制为24 KB 。因此,如果智能合约内容过多,会导致无法进行发布操作。

    用户1161110
  • java获取当前学期

    微醺
  • springboot gradle 使用过程中遇到的问题小结(5)

    1. @RequestMapping @PostMapping @GetMapping

  • 为什么大公司还在用过时的技术?

    本文出自一朋友给我的提问,于是博主呕心沥血给他花式洗脑了几个小时。忽然发现,应该还有许多朋友有同样的疑问。所以整理成文。

    Java技术栈
  • 本地缓存和分布式缓存的比较 堆污染

    分布式缓存一致性更好一点,本地缓存 每个实例都有自己的缓存,可能会存在不一致的情况。

  • 惊艳,Dubbo域名已改,也不再局限于Java!!

    看这个新官网还真清新亮丽,对比之前的老官网,这次调整还真不少,我想我有必要给大家重新介绍一下 Dubbo, 结合这次的变更下面给大家总结一下。

    Java技术栈
  • Java 11 快要来了,编译 & 运行一个命令搞定!

    在我们的认知里面,要运行一个 Java 源代码必须先编译,再运行,两步执行动作。而在未来的 Java 11 版本中,通过一个 java 命令就直接搞定了,如以下...

    Java技术栈
  • JVM下的Scala和Kotlin

    在JVM生态下流行的语言有好几种,最出名的应该就是Scala和Kotlin了。最近准备除了Java本身之外在学习一种JVM生态下的语言,Scala和Kotlin...

    春哥大魔王
  • 漫漫优化路,总会错几步!记一次接口优化!

    点击上方"IT牧场",选择"设为星标"技术干货每日送达!来源:www.cnblogs.com/cjsblog/p/10573215.html

    用户1516716
  • Objects类

    equals(Object a, Object b),这里感觉和Object中的equals作用相同。

扫码关注云+社区

领取腾讯云代金券