发表于: 2017-11-22 23:09:35
2 610
今天做的事情:
测试redis;
static String constr = "101.201.65.0" ;
public static Jedis getRedis(){
Jedis jedis = new Jedis(constr) ;
jedis.auth("123456");
return jedis;
}
public static void main(String[] args) {
Jedis j = Test.getRedis();
String output;
j.set("hello", "world");
output = j.get("hello");
System.out.println(output);
}
}
运行无错误。
思路: 使用jedis提供的缓存功能,在JDBC前面加上Redis,先从Redis中查询数据,如果Redis中没有该数据,就从数据库中查询,再把查询到的结果放入Redis中,下次再请求该接口的时候,就直接返回Redis中的数据。
序列化和反序列化的使用
接口查询到的数据是一个List集合,把集合对象通过序列化为字符串,放入到Redis中。使用的时候取出Redis中的数据,通过反序列化为对象使用。
注意:是将从数据库查出来的数据序列化成字符串放进redis,显示回页面时,redis将字符串反序列化回对象。
测试redis代码:
service层
public List ioslist() {
Jedis resource = jedis.getResource();
List ioslist = null;
if(resource.get("ioslist".getBytes())!=null){
//redis服务器本身支持二进制安全的类型,所以可以把一个java对象序列化后存储到redis中,也可以反序列化得放入redis中
//反序列化为对象
List unserialize = (List) SerializeUtil.unserialize(resource.get("ioslist".getBytes()));
System.out.println("输出redis反序列化后的缓存ioslist:"+unserialize);
return unserialize;
}else{
//在数据库查询数据 返回 再放进缓存中
ioslist = daoI.ioslist();
if(ioslist!=null){
//将对象序列化放进redis
resource.set("ioslist".getBytes(), SerializeUtil.serialize(ioslist));
System.out.println("从数据库查的redis的缓存数据");
}
}
return ioslist;
}
已经成功将从数据库查询的数据放进redis。下一步,测试数据库更新,缓存是否更新,更改代码。
public List ioslist() {
Jedis resource = jedis.getResource();
List ioslist = daoI.ioslist();
if(resource.get("ioslist".getBytes())!=null){
//redis服务器本身支持二进制安全的类型,所以可以把一个java对象序列化后存储到redis中,也可以反序列化得放入redis中
//反序列化为对象
List unserialize = (List) SerializeUtil.unserialize(resource.get("ioslist".getBytes()));
// SerializeUtil.serialize(resource.get("ioslist".getBytes()));
//如果redis的数据与从数据库查出最新的数据一样 resource.get("ioslist".getBytes(),SerializeUtil.serialize(ioslist)))
if(resource.get("ioslist".getBytes()).equals(unserialize)){
System.out.println("输出原redis反序列化后的缓存ioslist:"+unserialize);
return unserialize;
}else{
//否则 将最新的序列化redis,输出
List unserialize1 = (List) SerializeUtil.unserialize(resource.getSet("ioslist".getBytes(), SerializeUtil.serialize(ioslist)));
System.out.println("输出更新redis反序列化后的缓存ioslist:");
return unserialize1;
}
}else{
//在数据库查询数据 返回 再放进缓存中
if(ioslist!=null){
//将对象序列化放进redis
resource.set("ioslist".getBytes(), SerializeUtil.serialize(ioslist));
System.out.println("从数据库查的redis的缓存数据");
}
}
return ioslist;
}
控制台信息:
模拟数据穿透缓存的情况 ,看一下这个。
什么是缓存穿透?
一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
有一个比较巧妙的作法是,可以将这个不存在的key预先设定一个值。
比如,"key" , “&&”。
在返回这个&&值的时候,我们的应用就可以认为这是不存在的key,那我们的应用就可以决定是否继续等待继续访问,还是放弃掉这次操作。如果继续等待访问,过一个时间轮询点后,再次请求这个key,如果取到的值不再是&&,则可以认为这时候key有值了,从而避免了透传到数据库,从而把大量的类似请求挡在了缓存之中。
总结来看:
1、缓存穿透:查询一个必然不存在的数据。比如文章表,查询一个不存在的id,每次都会访问DB,如果有人恶意破坏,很可能直接对DB造成影响。
2、缓存失效:如果缓存集中在一段时间内失效,DB的压力凸显。这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。
当发生大量的缓存穿透,例如对某个失效的缓存的大并发访问就造成了缓存雪崩。
1000 线程
遇到的问题:
暂无
收获:
了解redis缓存与memcached区别与应用。
评论