博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
项目整合一级缓存和二级缓存
阅读量:2161 次
发布时间:2019-05-01

本文共 8238 字,大约阅读时间需要 27 分钟。

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)叫做二级缓存

4.0.0
com.learn
springboot2.0-redis
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
com.alibaba
fastjson
1.2.47
org.apache.commons
commons-lang3
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-cache
net.sf.ehcache
ehcache
2.9.1
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.1.1
mysql
mysql-connector-java
spring:  datasource:    url: jdbc:mysql://localhost:3306/test    username: root    password: 123456    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  redis:    database: 0    host: localhost    port: 6379    password: 123456    jedis:      pool:        max-active: 8        max-wait: -1        max-idle: 8        min-idle: 0    timeout: 10000      # 缓存配置读取  cache:    type: ehcache    ehcache:      config: classpath:app1_ehcache.xml
package com.learn.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;@Componentpublic 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.learn.service;import java.util.Set;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Component;@Componentpublic class RedisService {	@Autowired	private StringRedisTemplate stringRedisTemplate;	// public void set(String key, Object object, Long time) {	// stringRedisTemplate.opsForValue();	// // 存放String 类型	// if (object instanceof String) {	// setString(key, object);	// }	// // 存放 set类型	// if (object instanceof Set) {	// setSet(key, object);	// }	// // 设置有效期 以秒为单位	// stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);	// }	//	public void setString(String key, Object object) {		// 开启事务权限		stringRedisTemplate.setEnableTransactionSupport(true);		try {			// 开启事务 begin			stringRedisTemplate.multi();			String value = (String) object;			stringRedisTemplate.opsForValue().set(key, value);			System.out.println("存入完毕,马上开始提交redis事务");			// 提交事务			stringRedisTemplate.exec();		} catch (Exception e) {			// 需要回滚事务			stringRedisTemplate.discard();		}	}	public void setSet(String key, Object object) {		Set
value = (Set
) object; for (String oj : value) { stringRedisTemplate.opsForSet().add(key, oj); } } public String getString(String key) { return stringRedisTemplate.opsForValue().get(key); }}
package com.learn.service;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.alibaba.fastjson.JSONObject;import com.learn.entity.Users;import com.learn.mapper.UserMapper;@Servicepublic class UserService {	@Autowired	private EhCacheUtils ehCacheUtils;	private static final String CACHENAME_USERCACHE = "userCache";	@Autowired	private RedisService redisService;	@Autowired	private UserMapper userMapper;	public Users getUser(Long id) {		String key = this.getClass().getName() + "-" + Thread.currentThread().getStackTrace()[1].getMethodName()				+ "-id:" + id;		// 1.先查找一级缓存(本地缓存),如果本地缓存有数据直接返回		Users ehUser = (Users) ehCacheUtils.get(CACHENAME_USERCACHE, key);		if (ehUser != null) {			System.out.println("使用key:" + key + ",查询一级缓存 ehCache 获取到ehUser:" + JSONObject.toJSONString(ehUser));			return ehUser;		}		// 2. 如果本地缓存没有该数据,直接查询二级缓存(redis)		String redisUserJson = redisService.getString(key);		if (!StringUtils.isEmpty(redisUserJson)) {			// 将json 转换为对象(如果二级缓存redis中有数据直接返回二级缓存)			JSONObject jsonObject = new JSONObject();			Users user = jsonObject.parseObject(redisUserJson, Users.class);			// 更新一级缓存			ehCacheUtils.put(CACHENAME_USERCACHE, key, user);			System.out.println("使用key:" + key + ",查询二级缓存 redis 获取到ehUser:" + JSONObject.toJSONString(user));			return user;		}		// 3. 如果二级缓存redis中也没有数据,查询数据库		Users user = userMapper.getUser(id);		if (user == null) {			return null;		}		// 更新一级缓存和二级缓存		String userJson = JSONObject.toJSONString(user);		redisService.setString(key, userJson);		ehCacheUtils.put(CACHENAME_USERCACHE, key, user);		System.out.println("使用key:" + key + ",一级缓存和二级都没有数据,直接查询db" + userJson);		return user;	}}
package com.learn.api.controller;import java.util.HashSet;import java.util.Set;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import com.learn.entity.Users;import com.learn.service.RedisService;import com.learn.service.UserService;@RestControllerpublic class IndexControler {	@Autowired	private RedisService redisService;	@Autowired	private UserService userService;	@RequestMapping("/setString")	public String setString(String key, String value) {		// redisService.set(key, value, 60l);		redisService.setString(key, value);		return "success";	}	@RequestMapping("/getString")	public String getString(String key) {		return redisService.getString(key);	}	@RequestMapping("/setSet")	public String setSet() {		Set
set = new HashSet
(); set.add("yushengjun"); set.add("lisi"); redisService.setSet("setTest", set); return "success"; } @RequestMapping("/getUser") public Users getUser(Long id) { Users user = userService.getUser(id); return user; }}
package com;import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication@MapperScan("com.learn.mapper")@EnableCachingpublic class AppRedis {	public static void main(String[] args) {		SpringApplication.run(AppRedis.class, args);	}}

 

 

 

转载地址:http://ubkzb.baihongyu.com/

你可能感兴趣的文章
轻松看懂机器学习十大常用算法
查看>>
一个框架解决几乎所有机器学习问题
查看>>
特征工程怎么做
查看>>
机器学习算法应用中常用技巧-1
查看>>
机器学习算法应用中常用技巧-2
查看>>
通过一个kaggle实例学习解决机器学习问题
查看>>
决策树的python实现
查看>>
Sklearn 快速入门
查看>>
了解 Sklearn 的数据集
查看>>
用ARIMA模型做需求预测
查看>>
推荐系统
查看>>
TensorFlow-11-策略网络
查看>>
浅谈 GBDT
查看>>
如何选择优化器 optimizer
查看>>
一文了解强化学习
查看>>
CART 分类与回归树
查看>>
seq2seq 的 keras 实现
查看>>
seq2seq 入门
查看>>
什么是 Dropout
查看>>
用 LSTM 做时间序列预测的一个小例子
查看>>