昨天为止,差不多是把redis缓存应用方面学习完毕,有了初步的概念,虽然原理部分还不是很懂,但是至少已经可以用了,现在进行总结:

1.配置部分:

配置部分不难,主要是一些属性,备注上也写了。

2:初步使用

@SpringBootTest
public class DemoApplicationTests {

    @Autowired
    RedisTemplate<String,String> redisTemplate;
    @Test
    public void testString(){
        //操作String类型的数据
        ValueOperations<String, String> valueStr = redisTemplate.opsForValue();  //spring RedisTemplate中封装了很多的操作器,
                                                如 HashOperations,ZSetOperations等,分别能操作hash类型的数据结
                                                构和有序的Set类型数据结构,使用这些操作器能方便的对Map结构和Set结构数据进程操作。
//存储一条数据 valueStr.set("goodsProdu","长安"); //获取一条数据并输出 String goodsName = valueStr.get("goodsProdu"); System.out.println(goodsName); //存储多条数据 Map<String,String> map = new HashMap<>(); map.put("goodsName","福特汽车"); map.put("goodsPrice","88888"); map.put("goodsId","88"); valueStr.multiSet(map); //获取多条数据 System.out.println("========================================"); List<String> list = new ArrayList<>(); list.add("goodsName"); list.add("goodsPrice"); list.add("goodsId"); list.add("goodsProdu"); List<String> listKeys = valueStr.multiGet(list); for (String key : listKeys) { System.out.println(key); } }

3:进阶使用:数据库加上redis缓存,如果缓存中没有,再去数据库中查找  

server:
  port: 8081
  tomcat:
    uri-encoding: UTF-8

spring:
  http:
    encoding:
      charset: UTF-8
      force: true
      enabled: true

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    # mysql数据库位置
    url: jdbc:mysql://192.168.13.130:3306/ssm_sms?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

  redis:
    # Redis数据库索引(默认为0)
    database: 0
    # Redis服务器地址
    host: 192.168.13.130
    # Redis服务器连接端口
    port: 6379
    # Redis服务器连接密码(默认为空)
    password:
    # 连接超时时间(毫秒)
    timeout: 1000
    jedis.pool:
      # 连接池最大连接数(使用负值表示没有限制)
      max-active: 8
      # 连接池最大阻塞等待时间(使用负值表示没有限制)
      max-wait: -1
      # 连接池中的最大空闲连接
      max-idle: 8
      # 连接池中的最小空闲连接
      min-idle: 0
@Controller
public class GetUser {

    @Autowired
    UserMapper userMapper;

    @Autowired
    private RedisTemplate redisTemplate;





    @RequestMapping("/getUsers")
    @ResponseBody
    String getUsers(){
        long startTime;
        long endTime;
        startTime = System.currentTimeMillis();
        //获取redis中key="userJSON"的value
        String userJSON = (String)redisTemplate.opsForValue().get("userJSON");
        if(userJSON!=null){
            endTime = System.currentTimeMillis();
            System.out.println("取缓存成功,耗时" + (endTime-startTime) + "ms");
            return userJSON;
        }
        //在redis中获取不到则执行以下代码
        startTime = System.currentTimeMillis();
        List<User> userList = userMapper.getUserList();
        //将userList转为json字符串
        userJSON = JSONArray.fromObject(userList).toString();
        endTime = System.currentTimeMillis();
        //将查询结果存入redis中作缓存
        //四个参数从左至右分别为:key,value,有效时间,时间单位
        //这里即:创建一个key="userJSON",value=#{userJSON}的键值对,其有效时间是10秒
        redisTemplate.opsForValue().set("userJSON",userJSON,10, TimeUnit.SECONDS);
        System.out.println("取缓存失败,耗时" + (endTime-startTime) + "ms");
        return userJSON;
    }

    @RequestMapping("/getUsers2")
    @ResponseBody
    public ModelAndView getUsers2(){
        ModelAndView modelAndView =new ModelAndView();
        long listLength = redisTemplate.opsForList().size("userJSON");
        List<User> list =  redisTemplate.opsForList().range("userJSON",0,listLength);
        if(list.size()!=0){
        List<User> userList = userMapper.getUserList();
            System.out.println("取缓存成功,耗时");
            modelAndView.setViewName("wujifu");
            modelAndView.addObject("list",userList);
            return modelAndView;
        }
        //在redis中获取不到则执行以下代码
        List<User> userList = userMapper.getUserList();
        for(User user : userList){
            redisTemplate.opsForList().leftPush("userJSON",user);
        }
        modelAndView.setViewName("wujifu");
        modelAndView.addObject("list",userList);
        return modelAndView;
    }


}

 这里第一个方法是将缓存以jason的方式存入redis 取出来的时候转为字符串,但是我觉得太麻烦了,而且实际开发肯定不这么麻烦,所以我想直接用list的方式存进去,然后取出作为list输出在页面上,然后发现其实redis自己是支持很多类型的存取的:

String类型:

    @Test
    public void testString(){
        //设置键  获取键   get   set
        jedis.set("steve","stevetao");
        System.out.println("设置后值:"+jedis.get("steve"));
        //追加键       append
        jedis.append("steve"," Is Good Man");
        System.out.println("追加后值:"+jedis.get("steve"));
        //删除操作      del
        jedis.del("steve");
        System.out.println("删除后值:"+jedis.get("steve"));
        //不存在就保存,   setnx   msetnx
        jedis.setnx("steve","stevetao");
        System.out.println("设置后值:"+jedis.get("steve"));
        System.out.println("再次设置后值:"+jedis.setnx("steve","stevetao"));
        //截取字符串      substr
        System.out.println("截取后值:"+jedis.substr("steve",0,4));
        //设置多个键值对       mset    mget
        jedis.mset(new String[]{"zhangsan","123","lisi","1234"});
        System.out.println("多次设置后值:"+jedis.mget("zhangsan","lisi"));
        //递增递减          incr  decr      incrby  decrby
        jedis.incr("zhangsan");
        jedis.decr("lisi");
        System.out.println("递增递减后值:"+jedis.mget("zhangsan","lisi"));
        jedis.incrBy("zhangsan",6);
        jedis.decrBy("lisi",3);
        System.out.println("递增递减后值:"+jedis.mget("zhangsan","lisi"));
    }

List类型:

    @Test
    public void testList(){
        //尾添加 rpush          头添加  lpush
        jedis.lpush("books","java","C++","Ruby","Scala","python");
        jedis.rpush("language","java","C++","Ruby","Scala","python");
        //  -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
        System.out.println("头添加后books值:"+jedis.lrange("books",0,-1));
        System.out.println("尾添加后language值:"+jedis.lrange("language",0,-1));
        //尾部删除 rpop   头部删除 lpop
        System.out.println("删除的值为:"+jedis.lpop("books"));
        System.out.println("删除的值为:"+jedis.rpop("language"));
        System.out.println("头部删除后books值:"+jedis.lrange("books",0,-1));
        System.out.println("尾部删除后language值:"+jedis.lrange("language",0,-1));
        //尾部删除并头添加 rpoplpush
        jedis.rpoplpush("language","books");
        System.out.println("尾部删除并头添加后books值:"+jedis.lrange("books",0,-1));
        System.out.println("尾部删除并头添加后language值:"+jedis.lrange("language",0,-1));
        //区别:  只能给存在的list做添加,不能项lpush那样能新增list
        jedis.lpushx("books","php");
        jedis.lpushx("book","php");
        System.out.println("头添加后books值:"+jedis.lrange("books",0,-1));
        System.out.println("头添加后book值:"+jedis.lrange("book",0,-1));
        //获取集合长度 llen  指定索引的值 lindex   保留截取的值 ltrim
        System.out.println("books集合长度:"+jedis.llen("books"));
        System.out.println("books集合第二个数值:"+jedis.lindex("books",1));
        jedis.ltrim("books",0,2);
        System.out.println("截取后books值:"+jedis.lrange("books",0,-1));
    }

Hash类型

 

@Test
    public void testHash(){
        //适合字段:设值hset  取值hget(如果value是json字符串,类似保存对象)
        jedis.hset("student","name","zhangsan");
        System.out.println("student中name的值为:"+jedis.hget("student","name"));
        //适合对象:设值hmset      取值hmget
        Map<String,String> map = new HashMap<String,String>();
        map.put("name", "lisi");
        map.put("age", "36");
        jedis.hmset("teacher",map);
        System.out.println("teacher中name、age的值为:"+jedis.hmget("teacher","name","age"));
        //teacher是否存在键age  hexists
        if(jedis.hexists("teacher","age")){
            //给指定值增加4   hincrBy
            jedis.hincrBy("teacher","age",4);
            System.out.println("teacher中name、age的值为:"+jedis.hmget("teacher","name","age"));
        }
        //返回key的个数hlen      返回值hvals    返回键hkeys  键值对hgetAll
        jedis.hset("student","age","13");
        jedis.hset("student","qq","2246920330");
        jedis.hset("student","address","beijing");
        System.out.println("student中键的个数为:"+jedis.hlen("student"));
        System.out.println("student中所有的键为:"+jedis.hkeys("student"));
        System.out.println("student中所有的值为:"+jedis.hvals("student"));
        System.out.println("student中所有的键值对为:"+jedis.hgetAll("student"));
        //删除 hdel
        jedis.hdel("student",new String[]{"address","qq","age"});
        System.out.println("删除后,student中所有的键值对为:"+jedis.hgetAll("student"));
    }

Set类型

    @Test
    public void testSet(){
        //set中添加值 sadd      取值 smembers
        jedis.sadd("student","Jan","John","Steve","jack","lili","peter","Anna");
        jedis.sadd("girls","Jan","lili","Alice","Jeanne","Anna");
        System.out.println("排名不分先后:"+jedis.smembers("student"));
        //set个数 scard      是否存在某个值 sismember
        System.out.println("set集合的个数:"+jedis.scard("student"));
        System.out.println("student是否存在steve:"+jedis.sismember("student","Steve"));
        System.out.println("student是否存在stevetao:"+jedis.sismember("student","Stevetao"));
        //System.out.println(jedis.sscan("student","0").getResult());
        //删除指定的值 srem     随机删除并返回 spop
        System.out.println("删除指定的值Steve:"+jedis.srem("student","Steve"));
        System.out.println("删除的值为:"+jedis.spop("student"));
        System.out.println("再次排名不分先后:"+jedis.smembers("student"));
        //集合操作
        System.out.println("两个set的交集:"+jedis.sinter("student","girls"));
        System.out.println("两个set的并集:"+jedis.sunion("student","girls"));
        System.out.println("student对girls的差集:"+jedis.sdiff("student","girls"));
        System.out.println("girls对student的差集:"+jedis.sdiff("girls","student"));
        //集合操作并保存
        jedis.sinterstore("jiaoji","student","girls");
        jedis.sunionstore("bingji","student","girls");
        jedis.sdiffstore("chaji","student","girls");

        System.out.println("交集:"+jedis.smembers("jiaoji"));
        System.out.println("并集:"+jedis.smembers("bingji"));
        System.out.println("student对girls的差集:"+jedis.smembers("chaji"));
 

 ZSet类型

    @Test
    public void testZset(){
        jedis.zadd("math",75,"Jim");
        jedis.zadd("math",86,"Lina");
        jedis.zadd("math",52,"Dive");
        jedis.zadd("math",91,"Bobber");
        System.out.println("有序集合的成员数:"+jedis.zcard("math"));
        System.out.println("有序集合的成员:"+jedis.zrevrangeByScore("math",100,0));
        //返回set<Tuple>
        System.out.println("有序集合的成员:"+jedis.zrangeWithScores("math",0,100));
    }

 具体操作也可以看我例子;

还有关于redistemplate的意义,就是原本的模板是<String,String>类型的,改成用<String ,Object>来存储

https://www.cnblogs.com/songanwei/p/9274348.html

https://www.cnblogs.com/superfj/p/9232482.html

这两个网址中的例子都非常棒!

https://zhuanlan.zhihu.com/p/52631249

这是关于template的详解

其实不重写的话也没事,主要是序列化的问题啦,还有工具类,网上很多,就是将redistemplate的功能封装一下,使得操作更加简便

还有注解方式的使用

就两点

1.主函数那里要加开启注解的注解

2.

注释介绍

  • @Cacheable
  • @Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
  • @Cacheable 作用和配置方法
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个例如:
@Cacheable(value=”mycache”)
@Cacheable(value={”cache1”,”cache2”}
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合@Cacheable(value=”testcache”,key=”#userName”)
condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

@CachePut

  • @CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
  • @CachePut 作用和配置方法
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个@CachePut(value=”my cache”)
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合@CachePut(value=”testcache”,key=”#userName”)
condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存@CachePut(value=”testcache”,condition=”#userName.length()>2”)

@CacheEvict

  • @CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
  • @CacheEvict 作用和配置方法
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个@CacheEvict(value=”my cache”)
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合@CacheEvict(value=”testcache”,key=”#userName”)
condition缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存@CacheEvict(value=”testcache”,condition=”#userName.length()>2”)
allEntries是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存@CachEvict(value=”testcache”,allEntries=true)
beforeInvocation是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存@CachEvict(value=”testcache”,beforeInvocation=true)

@CacheConfig

所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,一个类中可能会有多个缓存操作,而这些缓存操作可能是重复的。这个时候可以使用@CacheConfig。

  1. @CacheConfig("books")
  2. public class BookRepositoryImpl implements BookRepository {
  3.  
  4. @Cacheable
  5. public Book findBook(ISBN isbn) {...}
  6. }
    //@Cacheable将在执行方法之前( #result还拿不到返回值)判断condition,如果返回true,则查缓存; 
    @Cacheable(value = "user", key = "#id", condition = "#id lt 10")
    public User conditionFindById(final Long id)
    
    //@CachePut将在执行完方法后(#result就能拿到返回值了)判断condition,如果返回true,则放入缓存; 
    @CachePut(value = "user", key = "#id", condition = "#result.username ne 'zhang'")
    public User conditionSave(final User user)
    
    //@CachePut将在执行完方法后(#result就能拿到返回值了)判断unless,如果返回false,则放入缓存;(即跟condition相反)
    @CachePut(value = "user", key = "#user.id", unless = "#result.username eq 'zhang'")
    public User conditionSave2(final User user)
    
    //@CacheEvict, beforeInvocation=false表示在方法执行之后调用(#result能拿到返回值了);且判断condition,如果返回true,则移除缓存;
    @CacheEvict(value = "user", key = "#user.id", beforeInvocation = false, condition = "#result.username ne 'zhang'")
    public User conditionDelete(final User user) 

    @Caching

    有时候我们可能组合多个Cache注解使用;比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;此时就需要@Caching组合多个注解标签了。

@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
public User save(User user) {

}

好了 redis缓存的基本使用到此结束!

01-21 23:08