EHCache 本地缓存

Redis 分布式缓存(可以共享)

一级 Redis 二级Ehcache    当redis挂了 有备胎

反之:

先走本地,本地没有再走网络  尽量少走Redis  效率会高一些

Redis与数据库的区别:

相同点 都是需要进行网络连接

不同点 是存放的介质  内存 和 硬盘

数据库需要做IO操作 性能比直接操作内存效率要低

Ehchache

不需要走网络 直接从内存中获取

由于Ehchache容器限制,会持久化在硬盘上,

Redis+ehCache实现两级级缓存

spring boot中集成了spring cache,并有多种缓存方式的实现,如:Redis、Caffeine、JCache、EhCache等等。但如果只用一种缓存,要么会有较大的网络消耗(如Redis),要么就是内存占用太大(如Caffeine这种应用内存缓存)。在很多场景下,可以结合起来实现一、二级缓存的方式,能够很大程度提高应用的处理效率。

内容说明:

缓存、两级缓存

spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明

spring boot + spring cache:RedisCache实现中的缺陷

caffeine简介

spring boot + spring cache 实现两级缓存(redis + caffeine)

缓存、两级缓存

简单的理解,缓存就是将数据从读取较慢的介质上读取出来放到读取较快的介质上,如磁盘-->内存。平时我们会将数据存储到磁盘上,如:数据库。如果每次都从数据库里去读取,会因为磁盘本身的IO影响读取速度,所以就有了像redis这种的内存缓存。可以将数据读取出来放到内存里,这样当需要获取数据时,就能够直接从内存中拿到数据返回,能够很大程度的提高速度。但是一般redis是单独部署成集群,所以会有网络IO上的消耗,虽然与redis集群的链接已经有连接池这种工具,但是数据传输上也还是会有一定消耗。所以就有了应用内缓存,如:caffeine。当应用内缓存有符合条件的数据时,就可以直接使用,而不用通过网络到redis中去获取,这样就形成了两级缓存。应用内缓存叫做一级缓存,远程缓存(如redis)叫做二级缓存

过期问题:

一级缓存 过期 时间 比二级要短一些

目录结构:

实体类:

注意一定要 序列号

package com.toov5.entity;

import java.io.Serializable;

import lombok.Data;

@Data
public class Users implements Serializable{
  private String name;
  private Integer age;
}

controller层

package com.toov5.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.toov5.entity.Users;
import com.toov5.service.UserService;

@RestController
public class IndexController {
    @Autowired
    private UserService userService;

    @RequestMapping("/userId")
    public Users getUserId(Long id){
        return userService.getUser(id);
    }

}

service层

package com.toov5.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Component;

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;

@Component
public class EhCacheUtils {

    // @Autowired
    // private CacheManager cacheManager;
    @Autowired
    private EhCacheCacheManager ehCacheCacheManager;

    // 添加本地缓存 (相同的key 会直接覆盖)
    public void put(String cacheName, String key, Object value) {
        Cache cache = ehCacheCacheManager.getCacheManager().getCache(cacheName);
        Element element = new Element(key, value);
        cache.put(element);
    }

    // 获取本地缓存
    public Object get(String cacheName, String key) {
        Cache cache = ehCacheCacheManager.getCacheManager().getCache(cacheName);
        Element element = cache.get(key);
        return element == null ? null : element.getObjectValue();
    }

    public void remove(String cacheName, String key) {
        Cache cache = ehCacheCacheManager.getCacheManager().getCache(cacheName);
        cache.remove(key);
    }

}
package com.toov5.service;

import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    //这样该方法支持多种数据类型
    public void set(String key , Object object, Long time){
        //开启事务权限
        stringRedisTemplate.setEnableTransactionSupport(true);
        try {
            //开启事务
            stringRedisTemplate.multi();

            String argString =(String)object;  //强转下
            stringRedisTemplate.opsForValue().set(key, argString);

            //成功就提交
            stringRedisTemplate.exec();
        } catch (Exception e) {
            //失败了就回滚
            stringRedisTemplate.discard();

        }
        if (object instanceof String ) {  //判断下是String类型不
            String argString =(String)object;  //强转下
            //存放String类型的
            stringRedisTemplate.opsForValue().set(key, argString);
        }
        //如果存放Set类型
        if (object instanceof Set) {
            Set<String> valueSet =(Set<String>)object;
            for(String string:valueSet){
                stringRedisTemplate.opsForSet().add(key, string);  //此处点击下源码看下 第二个参数可以放好多
            }
        }
        //设置有效期
        if (time != null) {
            stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
        }

    }
    //做个封装
    public void setString(String key, Object object){
        String argString =(String)object;  //强转下
        //存放String类型的
        stringRedisTemplate.opsForValue().set(key, argString);
    }
    public void setSet(String key, Object object){
        Set<String> valueSet =(Set<String>)object;
        for(String string:valueSet){
            stringRedisTemplate.opsForSet().add(key, string);  //此处点击下源码看下 第二个参数可以放好多
        }
    }

    public String getString(String key){
     return    stringRedisTemplate.opsForValue().get(key);
    }

}
package com.toov5.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.toov5.entity.Users;
import com.toov5.mapper.UserMapper;

import ch.qos.logback.core.net.SyslogOutputStream;
import io.netty.util.internal.StringUtil;

@Component
public class UserService {
    @Autowired
    private EhCacheUtils ehCacheUtils;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UserMapper userMapper;
    //定义个全局的cache名字
    private String cachename ="userCache";

    public Users getUser(Long id){
        //先查询一级缓存  key以当前的类名+方法名+id+参数值
        String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()
                + "-id:" + id;
        //查询一级缓存数据有对应值的存在 如果有 返回
        Users user = (Users)ehCacheUtils.get(cachename, key);
        if (user != null) {
            System.out.println("key"+key+",直接从一级缓存获取数据"+user.toString());
            return user;
        }
        //一级缓存没有对应的值存在,接着查询二级缓存
        // redis存对象的方式  json格式 然后反序列号
        String userJson = redisService.getString(key);
        //如果rdis缓存中有这个对应的值,修改一级缓存    最下面的会有的 相同会覆盖的
        if (!StringUtil.isNullOrEmpty(userJson)) {  //有 转成json
            JSONObject jsonObject = new JSONObject();//用的fastjson
            Users resultUser = jsonObject.parseObject(userJson,Users.class);
            ehCacheUtils.put(cachename, key, resultUser);
            return resultUser;
        }
        //都没有 查询DB
        Users user1 = userMapper.getUser(id);
        if (user1 == null) {
            return null;
        }
        //存放到二级缓存 redis中
        redisService.setString(key, new JSONObject().toJSONString(user1));
        //存放到一级缓存 Ehchache
        ehCacheUtils.put(cachename, key, user1);
        return user1;
    }

}

启动类:

package com.toov5.app;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching //开启缓存
@MapperScan(basePackages={"com.toov5.mapper"})
@SpringBootApplication(scanBasePackages={"com.toov5.*"})
public class app {
   public static void main(String[] args) {
    SpringApplication.run(app.class, args);
}

}

app1.ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

	<diskStore path="java.io.tmpdir/ehcache-rmi-4000" />

	<!-- 默认缓存 -->
	<defaultCache maxElementsInMemory="1000" eternal="true"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="true" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">
	</defaultCache>

	<!-- demo缓存 --><!-- name="userCache" 对应我们在 @CacheConfig(cacheNames={"userCache"}) !!!!! -->
	<!--Ehcache底层也是用Map集合实现的 -->
	<cache name="userCache" maxElementsInMemory="1000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true"
		diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000"
		diskPersistent="false" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU">  <!-- LRU缓存策略 -->
		<cacheEventListenerFactory
			class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
		<!-- 用于在初始化缓存,以及自动设置 -->
		<bootstrapCacheLoaderFactory
			class="net.sf.ehcache.distribution.RMIBootstrapCacheLoaderFactory" />
	</cache>
</ehcache>

yml

###端口号配置
server:
  port: 8080
###数据库配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    test-while-idle: true
    test-on-borrow: true
    validation-query: SELECT 1 FROM DUAL
    time-between-eviction-runs-millis: 300000
    min-evictable-idle-time-millis: 1800000
# 缓存配置读取
  cache:
    type: ehcache
    ehcache:
      config: classpath:app1_ehcache.xml

  redis:
    database: 0
    host:  192.168.91.3
    port:  6379
    password:  123
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
    timeout: 10000

运行结果:

后面的访问,在控制台打印:

其中一定要注意

这里的 两级缓存时间问题  执行设置二级缓存时候 需要时间的  所以这两个时间设置问题一定要注意了哦

Spring Boot2.0+Redis+Ehcache实现二级缓存的更多相关文章

  1. 【Redis】SpringBoot+Redis+Ehcache实现二级缓存

    一.概述 1.1 一些疑惑? 1.2 场景 1.3 一级缓存.两级缓存的产生 1.4 流程分析 二.项目搭建 一.概述 1.1 一些疑惑? Ehcache本地内存 Redis 分布式缓存可以共享 一级 ...

  2. SpringBoot30 整合Mybatis-Plus、整合Redis、利用Ehcache实现二级缓存、利用SpringCache和Redis作为缓存

    1 环境说明 JDK: 1.8 MAVEN: 3. SpringBoot: 2.0.4 2 SpringBoot集成Mybatis-Plus 2.1 创建SpringBoot 利用IDEA创建Spri ...

  3. Hibernate4+EhCache配置二级缓存

    本文主要讲一讲Hibernate+EhCache配置二级缓存的基本使用方法 (有关EhCache的基础介绍可参见:http://sjsky.iteye.com/blog/1288257 ) Cache ...

  4. 【redis】4.spring boot集成redis,实现数据缓存

    参考地址:https://spring.io/guides/gs/messaging-redis/ ================================================== ...

  5. mybatis(4)_二级缓存深入_使用第三方ehcache配置二级缓存

    增删改对二级缓存的影响 1.增删改也会清空二级缓存 2.对于二级缓存的清空实质上是对value清空为null,key依然存在,并非将Entry<k,v>删除 3.从DB中进行select查 ...

  6. Spring Boot2.0 整合 Kafka

    Kafka 概述 Apache Kafka 是一个分布式流处理平台,用于构建实时的数据管道和流式的应用.它可以让你发布和订阅流式的记录,可以储存流式的记录,并且有较好的容错性,可以在流式记录产生时就进 ...

  7. spring boot 2.0(一)权威发布spring boot2.0

    Spring Boot2.0.0.RELEASE正式发布,在发布Spring Boot2.0的时候还出现一个小插曲,将Spring Boot2.0同步到Maven仓库的时候出现了错误,然后Spring ...

  8. Spring Boot2.0 设置拦截器

    所有功能完成 配置登录认证 配置拦截器 在spring boot2.0 之后 通过继承这个WebMvcConfigurer类 就可以完成拦截 新建包com.example.interceptor; 创 ...

  9. Spring Boot2.0 静态资源被拦截问题

    在Spring Boot2.0+的版本中,只要用户自定义了拦截器,则静态资源会被拦截.但是在spring1.0+的版本中,是不会拦截静态资源的. 因此,在使用Spring Boot2.0+时,配置拦截 ...

随机推荐

  1. 区间翻转(codevs 3243)

    题目描述 Description 给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列 输入描述 Input Description 第一行一个数N,下一行N个数表示原 ...

  2. 转载 gdb调试程序

    转载自csdn,作者haoel,链接http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一 ...

  3. WAMP本地环境升级php版本--第二次尝试

    wamp 环境下 php5.6.25 升级php7.1.17 实践 本文参考:https://www.cnblogs.com/hubaohua1588/p/6884146.html来进行操作. 1.从 ...

  4. spring data jpa使用原生sql查询

    spring data jpa使用原生sql查询 @Repository public interface AjDao extends JpaRepository<Aj,String> { ...

  5. Java中String字符串toString()、String.valueOf()、String强转、+ ""的区别

    Object#toString(): Object object = getObject(); System.out.println(object.toString()); 在这种使用方法中,因为ja ...

  6. sql中Cast()函数的用法

    一.MYSQL 只需要一个Cast()函数就能搞定.其语法为:Cast(字段名 as 转换的类型 ),其中类型可以为: BINARY[(N)]CHAR[(N)] 字符型DATE  日期型DATETIM ...

  7. MySQL 为日期增加一个时间间隔

    set @dt = now(); select date_add(@dt, interval 1 day);   - 加1天 select date_add(@dt, interval 1 hour) ...

  8. 微软CIO如何与业务部门打交道?

    微软公司副总裁兼CIO Tony Scott是一个非常智慧的人,他拒绝和CEO讨论IT成本的问题,认为IT不应该谈论成本,而是应该谈论IT提供服务的价值.在满足业务部门需求.为业务部门提供适当的IT支 ...

  9. win7系统使用engine进行开发报错,“未能加载文件或程序集”

    http://www.gisall.com/wordpress/?p=7161 使用vs2010加 arcengine 开发winfrom应用,新建了uc,拖了几个控件后,编译,报未能加载文件或程序集 ...

  10. svm、logistic regression对比

    相同点:都是线性分类算法 不同点: 1.损失函数不同 LR:基于“给定x和参数,y服从二项分布”的假设,由极大似然估计推导 SVM: hinge loss + L2 regularization的标准 ...