ローカルキャッシュと分散キャッシュEhcacheのRedisのご紹介

まず、ローカルキャッシュEhcacheのご紹介

1.1 Ehcacheのはどのようなものです(JVMは、組み込みのキャッシュ)

FrameworkはオープンソースのEhcacheの純粋なJavaのキャッシュでありキャッシュデータがメモリ内部に格納することができる、それがハードディスクに保存することができます。

二次キャッシュ、Redisのサーバーがダウンした場合、あなたはキャッシュehcacheを確認することができますようにehcacheをしてみましょう。

1.2、利用プロジェクト

スタートクラスプラス:@EnableCachin、オープンehcacheをキャッシュモード

@CacheConfig(cacheNames = "userCache")
public interface UserMapper {
	@Select("SELECT ID ,NAME,AGE FROM users where id=#{id}")
	@Cacheable
	List<Users> getUser(@Param("id") Long id);
}

@Cacheableプラス注釈付きメソッドは、キャッシュを表し

@CacheConfigはuserCacheにキャッシュ設定、キーを作成することを意味します

 1.3、RedisのとEhcacheのキャッシング差

  • 単一のアプリケーション、またはEhcacheの持つアプリケーションを、要求の厳しいキャッシュへのアクセスの場合、
  • システムが大きい場合は、共有キャッシュ、分散配置、大きなキャッシュの内容、提案のRedisがあります。

 

第二に、使用のRedis + Ehcacheのは、分散キャッシュ(二次キャッシュ)を実装します

2.1、回路図:

 

 

2.2、使用した二次キャッシュ

A(Ehcacheの)、2( Redisの)ローカルネットワークウォークがありません

その上のRedis、カフェイン、JCacheの、Ehcacheのと:ブート統合春春のキャッシュ、およびキャッシュのような、さまざまな方法を達成するために持っています。しかし、一つだけのキャッシュは、いずれかの大規模なネットワークの消費量を(例えばRedisのような)があるだろう、または(例えばカフェイン、このアプリケーションのメモリキャッシュとして)メモリフットプリントが大きすぎるの場合

二次キャッシュ原理:Redisのネットワーク使用量、修飾データバッファはアプリケーション内で、このようにしてキャッシュ2つのレベルを形成する、代わりのRedisのを取得するためにネットワークを介して、直接使用することができ、目的のアクセスRedisのを低減することですまた、アクセス速度向上させることができ、圧力(なしEhcacheのメモリオーバーフローは、Ehcacheのは、ネットワークに行きません)

プロセスの説明:

(1)查一级缓存Ehcache一级缓存是否存在值,存在则直接返回,不用走网络,很快;

(2)一级缓存没有,查二级缓存Redis:二级缓存有值——>更新一级缓存——>返回值;

(3)一级缓存没有,查二级缓存Redis:二级缓存无值——>查数据库——更新二级缓存Redis——>更新一级缓存——>返回值。

几个问题:

(1)过期时间怎么控制(一级和二级的如何同步)?

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

......

(2)redis和ehcache缓存值不同步,怎么解决?

定时Job、MQ通知

.......

(3)其他问题

.....待整理

 

2.3、代码实现二级缓存

注意:可以把以下代码封装以下,封装成一个注解,一个注解搞定!

Ehcache工具类:

@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);
	}

}

项目整合Ehcache环境:

@Service
public class UserService {
	@Autowired
	private EhCacheUtils ehCacheUtils;
	private static final String CACHENAME_USERCACHE = "userCache";
	@Autowired
	private RedisService redisService;
	@Autowired
	private UserMapper userMapper;//DB

	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) {//如果DB查不到
			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;
	}

}

 

三、Redis

redis有16个库,默认连接第一个库

 3.1、Redis的一些应用场景

(1)令牌生成(临时 有效期)

(2)短信验证(短信也有有效期)

(3)缓存,热点数据(减轻查询数据库压力)

(4)分布式锁(使用ZK或者Redis实现)

(5)网站计数器(因为redis单线程,在高并发时刻保证全局count唯一性)

(6)实现消息队列(不推荐)——发布-订阅

3.2、Redis基本数据类型(5种)

(1)String(字符串)——常用

应用场景:普通key——value存储都可以

redis 127.0.0.1:6379> SET mykey "redis" 
OK 
redis 127.0.0.1:6379> GET mykey 
"redis"

(2)List(列表)

应用场景:比如关注列表、粉丝列表

//LPUSH :存
redis 127.0.0.1:6379> LPUSH runoobkey redis
(integer) 1
redis 127.0.0.1:6379> LPUSH runoobkey mongodb
(integer) 2
redis 127.0.0.1:6379> LPUSH runoobkey mysql
(integer) 3
//LRANGE :查
redis 127.0.0.1:6379> LRANGE runoobkey 0 10

(1)"mysql"
(2)"mongodb"
(3) "redis"

(3)Hash(字典)

对应的Value内部是一个HashMap 或者数组

应用场景:当Hash成员少时为了节省空间Value采用数组存储;成员数大时Value自动转成HashMap

127.0.0.1:6379>  HMSET runoobkey name "redis tutorial" 
127.0.0.1:6379>  HGETALL runoobkey
(1)"name"
(2) "redis tutorial"
(3)"description"
(4) "redis basic commands for caching"
(5)"likes"
(6)"20"
(7)"visitors"
(8) "23000"

(4)Set(集合)——无序集合

RedisSetstring类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据

redis 127.0.0.1:6379> SADD runoobkey redis
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mongodb
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 1
redis 127.0.0.1:6379> SADD runoobkey mysql
(integer) 0
redis 127.0.0.1:6379> SMEMBERS runoobkey

(1)"mysql"
(2)"mongodb"
(3)"redis"

(5)Sorted Set(有序集合)——有序集合

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。每个元素都会关联一个double类型的分数,正是通过分数来为集合中的成员进行从小到大的排序(有序集合成员唯一,但分数(score)却可以重复)

redis 127.0.0.1:6379> ZADD runoobkey 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD runoobkey 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES

(1) "redis"
(2) "1"
(3) "mongodb"
(4)"2"
(5) "mysql"
(6) "4"

 

3.3、SpringBoot整合redis

(1)Maven依赖

(2)配置文件

spring:
  redis:
    //database代表存在哪个库,默认第一个库
    database: 0
    host: 132.232.44.194
    port: 6379
    password: 123456
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 8
        min-idle: 0
    timeout: 10000

(3)代码整合

@RestController
public class IndexControler {

	@Autowired
	private RedisService redisService;

	@RequestMapping("/setString")
	public String setString(String key, String value) {
		redisService.set(key, value, 60l);
		return "success";
	}

	@RequestMapping("/getString")
	public String getString(String key) {
		return redisService.getString(key);
	}

	@RequestMapping("/setSet")
	public String setSet() {
		Set<String> set = new HashSet<String>();
		set.add("yushengjun");
		set.add("lisi");
		redisService.setSet("setTest", set);
		return "success";
	}
}
@Component
public class RedisService {

	@Autowired
	private StringRedisTemplate stringRedisTemplate;

	public void set(String key, Object object, Long time) {
		// 存放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) {
		// 如果是String 类型
		String value = (String) object;
		stringRedisTemplate.opsForValue().set(key, value);
	}

	public void setSet(String key, Object object) {
		Set<String> value = (Set<String>) object;
		for (String oj : value) {
			stringRedisTemplate.opsForSet().add(key, oj);
		}
	}

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

}

 

 

发布了52 篇原创文章 · 获赞 116 · 访问量 5万+

おすすめ

転載: blog.csdn.net/RuiKe1400360107/article/details/103649938