(一)RedisTemplate各种数据类型演示(基于Junit)


1.key value类型



@Autowired
private RedisTemplate redisTemplate;
/
设置值
ValueTest类
*/
@Test
public void setValue() {
//redis是key-value格式的数据库
//redisTemplate.boundValueOps(“valuetest”).set(“赵云”);

//参数一:指定key 参数二:有效时间 参数三:时间单位:秒、分钟等
//时间过了就会被清掉
redisTemplate.boundValueOps(“valuetest”).set(“关羽”, 30l, TimeUnit.
SECONDS);

}
/

基于key获取value值
ValueTest类
/
@Test
public void getValue() {
//指定key获取value
System.out.println(redisTemplate.boundValueOps(“valuetest”).get());
}
/**
基于key删除value
ValueTest类
/
@Test
public void deleteValue() {
//redis是key-value格式的数据库
redisTemplate.delete(“valuetest”);
}
}

2.set集合

@Autowired
private RedisTemplate redisTemplate;
/
设置值
SetTest.class
*/
@Test
public void setValue() {
//第一个参数是指定key值
redisTemplate.boundSetOps(“settest”).add(“唐僧”);
redisTemplate.boundSetOps(“settest”).add(“悟空”);
redisTemplate.boundSetOps(“settest”).add(“八戒”);
redisTemplate.boundSetOps(“settest”).add(“悟净”);

}
/

根据key取值,取出的值是无序的,
SetTest.class
/
@Test
public void getValue() {
System.out.println(redisTemplate.boundSetOps(“settest”).members());
}
/**
指定value值删除值
SetTest.class
/
@Test
public void deleteOne() {
redisTemplate.boundSetOps(“settest”).remove(“唐僧”);
}
/
全部删除,指定key删除全部的值
SetTest.class
*/
@Test
public void** deleteValue() {
//redis是key-value格式的数据库
redisTemplate.delete(“settest”);
}

3.list集合

Redis中的List其实就是链表(redis 使用双端链表实现的 List),相信学过数据结构知识的人都应该能理解其结构。
使用 List 结构,我们可以轻松地实现最新消息排行等功能(比如新浪微博的 TimeLine )。List 的另一个应用就是消息队列,可以利用 List 的 PUSH 操作,将任务存在 List 中,然后工作线程再用 POP 操作将任务取出进行执行。
list麻烦点.因为list是有序的,可以选择在当前值的前面插入值,或者是在当前值的后面来插入值


@Autowired
private RedisTemplate redisTemplate;
/
在左面加值
ListTest.class
*/
@Test
public void setLeftValue() {
//redis是key-value格式的数据库 金莲 大郎 武松
redisTemplate.boundListOps(“listtest”).leftPush(“武松”);
redisTemplate.boundListOps(“listtest”).leftPush(“大郎”);
redisTemplate.boundListOps(“listtest”).leftPush(“金莲”);

}
/

在右面加值
ListTest.class
/
@Test
public void setRightValue() {
//redis是key-value格式的数据库 金莲 大郎 武松 武松 大郎 金莲
redisTemplate.boundListOps(“listtest”).rightPush(“武松”);
redisTemplate.boundListOps(“listtest”).rightPush(“大郎”);
redisTemplate.boundListOps(“listtest”).rightPush(“金莲”);

}
/**
取值
ListTest.class
/
@Test
public void getValue() {
//.range(0, 10)); 中第0个开始查询,查第十个
System.out.println(redisTemplate.boundListOps(“listtest”).range(0, 10));
}
/
删除指定的元素
ListTest.class
*/
@Test
public void delete() {
//redis是key-value格式的数据库 [金莲, 大郎, 武松, 武松, 大郎, 金莲]
//参数一:删除几个指定元素,这样是删除两个金莲
redisTemplate.boundListOps(“listtest”).remove(2l, “金莲”);
}

@Test
public void** deleteValue() {
//redis是key-value格式的数据库
redisTemplate.delete(“listtest”);
}

4.hash散列类型

/**

  • 基于模板类操作redis, 所以需要注入进来

*/

@Autowired

private RedisTemplate redisTemplate;

/**

  • 添加值
  • HashTest.class

    */
    @Test

public void setValue() {

redisTemplate.boundHashOps(“hashtest”).put(“name1”, “宝玉”);

redisTemplate.boundHashOps(“hashtest”).put(“name2”, “黛玉”);

redisTemplate.boundHashOps(“hashtest”).put(“name3”, “宝钗”);

}

/**

  • 各种获取
  • HashTest.class

    */
    @Test

public void getValue() {

//基于key获取value

System.out.println(redisTemplate.boundHashOps(“hashtest”).get(“name1”));

//获取所有的key

System.out.println(redisTemplate.boundHashOps(“hashtest”).keys());

//获取所有的value

System.out.println(redisTemplate.boundHashOps(“hashtest”).values());

}

/**

  • 基于小key删除redis数据
  • HashTest.class

    */
    @Test

public void delete() {

//redis是key-value格式的数据库 [金莲, 大郎, 武松, 武松, 大郎, 金莲]

//基于key删除

redisTemplate.boundHashOps(“hashtest”).delete(“name1”);

}

/**

  • 基于大Key删除整个redis数据
    */
    @Test

public void deleteValue() {

//redis是key-value格式的数据库

redisTemplate.delete(“hashtest”);

}

5.RedisConnection

/*Spring Boot 提供了RedisConnection 抽象,用于低级别API 操作Redis ,具体实现有JRedis或者Lettuce

*由于Redis 所有数据结构都是二进制的.Spring Boot 对StringRedis Template 做了一定抽象,通过内置的序列化机制将字符串序列化成byte 。Spring Boot 也提供了RedisTemplate

  • , 默认使用Java 的序列化机制将Redis 数据序列化成byte 。RedisConnection 提供了低级别的API 操作,用byte 数组作为参数操作Red is 服务器。
    * 在这个例子中, 也可以直接将RedisConnection 转为StringRedi sConnection:

    ((StringRedisConnection) conn ection ) . set (key, value );
    /
    @RequestMapping(“/connectionset.html”)

public @ResponseBody String connectionSet (final String key,final String value) throws Exception{

redisClient.execute(new RedisCallback(){

  1. **public **Object doInRedis(RedisConnection connection) **throws **DataAccessException {
  2. **try **{
  3. connection.set(key.getBytes(**"UTF-8"**), value.getBytes(**"UTF-8"**));
  4. } **catch **(UnsupportedEncodingException e) {
  5. **throw new **RuntimeException(e);
  6. }<br /> **return null**;
  7. }<br /> <br /> });<br /> <br /> **return "success"**;


}



(二)在项目中实现

1.Spring整合SpringDataRedis

思考依赖存放位置问题: 建议依赖放在common工程,因为多个模块可能都会用到缓存,如果只是考虑只用一次缓存,不思考通用问题的话,坐标依赖就放dao层合适
理由:因为缓存也是操作数据的,正常情况下,操作数据都是在dao层来实现.
但是如果是只有这一个功能使用,也可以把依赖放在service层.


2.给首页添加缓存功能

功能其实很简单,先把redis整合在项目之后才能接着开始
1.先加入依赖 依赖参考上面的入门demo演示,完全可以拿过来
2.再加入SpringRedis.xml文件 参考上面入门demo ,然后修改下路径
3.再加入properties文件 参考上面入门demo
4.把RedisTemplate模版注入进你所需要的编写的service层代码里面就开始写业务代码了

思考用map结构是因为: 前台需要通过categoryid来查询获取广告数据, 这样的情况和map结构很类似,


思路,先从缓存里面尝试着查询数据,如果缓存没有再去数据库里面查询,再放入redis里面

@Autowired

private RedisTemplate redisTemplate;

/**

把广告数据放入redis缓存里面
思路:思路,先从缓存里面尝试着查询数据,如果缓存没有再去数据库里面查询,再放入redis里面
*数据类型用hash类型的,可以hash的基于key(广告的类型)来获取value(广告的具体信息)

ContentServiceImpl.class
**
@param categoryId

*
@return
*
/
@Override

public List findByCategoryId(Long categoryId) {

/*

  1. 1.从缓存中查询数据,基于广告分类查询广告数据<br /> 指定一个大key : content 基于categoryId来获取值<br /> */<br /> List<TbContent> contentList = (List<TbContent>) **redisTemplate**.boundHashOps(**"content"**).get(categoryId);
  2. //2.没有从缓存中获取数据<br /> **if **(contentList == **null**) {
  3. System.**_out_**.println(**"从数据库中获取广告数据"**);<br />
  4. TbContentExample example = **new **TbContentExample();<br />
  5. Criteria criteria = example.createCriteria();<br /> //基于分类id查询广告<br /> criteria.andCategoryIdEqualTo(categoryId);
  6. criteria.andStatusEqualTo(**"1"**);//有效状态<br /> example.setOrderByClause(**"sort_order"**);
  7. contentList = **contentMapper**.selectByExample(example);<br />
  8. //3.将结果放入缓存<br /> **redisTemplate**.boundHashOps(**"content"**).put(categoryId, contentList);

} else {

  1. System.**_out_**.println(**"从缓存中获取广告数据"**);

}

return contentList;

}





3.广告数据发生变化怎么更新redis缓存

思路:先清除指定类型的广告数据,在访问存在广告页面,将最新的广告数据重新加入缓存。
细节中
改变广告可能改变广告类型.
开始从广告的增删改查开始下手操作

/
新增操作
清除redis:目的是清理所有的缓存,防止数据错乱,
key就是传过来的值
ContentServiceImpl.class
*
@param content
*/
@Override
public void add(TbContent content) {
contentMapper.insert(content);
//清除指定广告分类的缓存数据
redisTemplate.boundHashOps(“content”).delete(content.getCategoryId());
}


/

修改
执行删除之前先把category查询到
修改需要判断一下
ContentServiceImpl.class
*@param content
/
@Override
public void update(TbContent content){
//先查询原来广告分类id
Long categoryId = contentMapper.selectByPrimaryKey(content.getId()).getCategoryId();
//清除原来广告分类数据(上面查询的是原来的数据,防止数据错乱,先全部清理掉)
redisTemplate.boundHashOps(“content”).delete(categoryId);

contentMapper.updateByPrimaryKey(content);

//判断修改前和修改后广告分类是否一致,如果不一致就清理
//longValue是将包装数据类型转换成基本数据类型
if(categoryId.longValue()!=content.getCategoryId().longValue()) {
//清除改变之后的广告分类数据
redisTemplate.boundHashOps(“content”).delete(content.getCategoryId());
}
}

/**
批量删除广告
为什么先删除缓存再清理, 考虑极端的线程问题了
在删除的时候万一别人访问了怎么办,(所以先清理缓存再删除)
ContentServiceImpl.class
**
@param ids
*/
@Override
public void delete(Long[] ids) {
for**(Long id:ids){
//先查询广告数据
TbContent content = contentMapper.selectByPrimaryKey(id);
Long categoryId = content.getCategoryId();
//清除原来广告分类数据(上面查询的是原来的数据,防止数据错乱,先全部清理掉)
redisTemplate.boundHashOps(“content”).delete(categoryId);
contentMapper.deleteByPrimaryKey(id);

}
}

4.查询文章,没有就查询缓存


/**

  • 根据ID查询实体
  • 先从redis里面获取,如果有的话就直接返回,如果没有就从数据库里面查询,

    • 再设置进redis里面,再返回
      需要注意,修改和删除都得清理redis缓存,否则会出现数据错乱问题
  • @param **id

    *
    @return

    */
    public **Article findById(String id) {

    //1.判断缓存中是否有文章

    Article article = (Article)redisTemplate.opsForValue().get(“article_”+id);

    if(article == null){

    1. System.**_out_**.println(**"去数据库获取的"**);
    2. //2.去数据库查询
    3. article = **articleDao**.findById(id).get();
    4. //3.存入redis(设置过期时间)<br /> **redisTemplate**.opsForValue().set(**"article_"**+id,article,30, TimeUnit.**_SECONDS_**);<br />

    }else{

    1. //只是用于演示
    2. System.**_out_**.println(**"从缓存获取的"**);

    }

    return article;

}

/**

  • 修改
  • @param **article
    *
    /

public void update(Article article) {

articleDao.save(article);

//清除缓存

redisTemplate.delete(“article_”+article.getId());

}

/**

  • 删除
  • @param **id
    *
    /

public void deleteById(String id) {

articleDao.deleteById(id);

//清除缓存

redisTemplate.delete(“article_”+id);

}