Redis-SpringBoot整合(注解和模板)

Posted wqq-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis-SpringBoot整合(注解和模板)相关的知识,希望对你有一定的参考价值。

SpringBoot中使用Redis的两种方式:RedisTemplate,   注解

 

这里使用的是IDEA, 项目为maven风格的SpringBoot

 

一.pom.xml依赖:

添加Redis依赖和JPA依赖

这里我开始犯了个错误,就是没有依赖jpa包,导致无法使用RedisTemplate类

        <!--Redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

 

二.application.properties

在application.properties中添加Redis数据库的配置信息,使得可以访问Redis数据库

################################Redis配置##################################
#Redis数据库索引
spring.redis.database=0
#Redis服务器地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码
spring.redis.password=
#连接池最大连接数
spring.redis.jedis.pool.max-active=20
#连接池中的最大空闲连接
spring.redis.jedis.pool.min-idle=5
#连接超时时间(毫秒)
spring.redis.timeout=2000

 

_________________________________________________________________________

通过Redis进行数据缓存的方式有两种,

    一种是使用Redis模板进行数据缓存,
    一种是通过注解,让Spring框架自动进行数据缓存

 

首先是第一种, 使用RedisTemplate编写RedisUtil工具,来进行数据缓存操作

三.使用RedisTemplate模板进行数据操作

完成上面的配置之后,其实就可以直接使用RedisTemplate模板操作数据了

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class SpringbootApplicationTests {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void contextLoads() {
        stringRedisTemplate.opsForValue().set("test","123");
        String test = stringRedisTemplate.opsForValue().get("test");
        System.out.println(test);
    }
}

 

四.自定义RedisTemplate

若使用默认的RedisTemplate配置,其泛型为RedisTemplate<Object,Object>, 不方便保存对象

这时就要自定义模板和序列化处理程序,使得Redis能够保存对象

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);//设置链接工厂

        RedisSerializer stringSerializer = new StringRedisSerializer();//初始化string序列化器
        redisTemplate.setKeySerializer(stringSerializer);//设置key使用string序列化方式
        redisTemplate.setHashKeySerializer(stringSerializer);//设置哈希键使用string的序列化方式

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //初始化jackson序列化方式

        ObjectMapper om = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);//设置
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        return redisTemplate;
    }

 

五.自定义RedisUtil

在完成上面的自定义配置后,就可以使用RedisTemplate来写操作Redis的工具了

此段参考:https://www.jianshu.com/p/b9154316227e

  1 package com.springboottest.springboot.util;
  2 
  3 import org.springframework.beans.factory.annotation.Autowired;
  4 import org.springframework.data.redis.core.RedisTemplate;
  5 import org.springframework.data.redis.core.StringRedisTemplate;
  6 import org.springframework.stereotype.Component;
  7 import org.springframework.util.CollectionUtils;
  8 
  9 import java.util.List;
 10 import java.util.Map;
 11 import java.util.Set;
 12 import java.util.concurrent.TimeUnit;
 13 
 14 /**
 15  * Redis工具
 16  *
 17  */
 18 
 19 @Component
 20 public class RedisUtil {
 21     @Autowired
 22     RedisTemplate<String,Object> redisTemplate;
 23 
 24     @Autowired
 25     StringRedisTemplate stringRedisTemplate;
 26 
 27     //=========================common=============================
 28     /**
 29      * 指定缓存失效时间
 30      * @param key 键
 31      * @param time 时间(秒)
 32      * @return
 33      */
 34     public boolean expire(String key,long time){
 35         try{
 36             if(time>0)
 37                 redisTemplate.expire(key,time, TimeUnit.SECONDS);
 38             return true;
 39         }catch (Exception e){
 40             e.printStackTrace();
 41             return false;
 42         }
 43     }
 44 
 45     /**
 46      * 判断key是否存在
 47      * @param key 键
 48      * @return true 存在 false 不存在
 49      */
 50     public boolean hasKey(String key){
 51         try{
 52             return redisTemplate.hasKey(key);
 53         }catch (Exception e){
 54             e.printStackTrace();
 55             return false;
 56         }
 57     }
 58 
 59     /**
 60      * 删除缓存
 61      * @param key 可以传一个值或多个
 62      */
 63     @SuppressWarnings("unchecked")
 64     public void del(String... key){
 65         if(key!=null && key.length>0){
 66             if(key.length==1)  //如果参数只有一个
 67                 redisTemplate.delete(key[0]); //删除第一个
 68             else
 69                 redisTemplate.delete(CollectionUtils.arrayToList(key)); //不止一个参数,则将其数组转化成List传递进方法
 70         }
 71     }
 72 
 73     //=========================string=============================
 74     /**
 75      * 普通缓存获取
 76      * @param key 键
 77      * @return 78      */
 79     public Object get(String key){
 80         return key==null?null:redisTemplate.opsForValue().get(key);
 81     }
 82 
 83     /**
 84      * 普通缓存放入
 85      * @param key 键
 86      * @param value 值
 87      * @return true 成功 false 失败
 88      */
 89     public boolean set(String key,Object value){
 90         try{
 91             redisTemplate.opsForValue().set(key,value);
 92             return true;
 93         }catch (Exception e){
 94             e.printStackTrace();
 95             return false;
 96         }
 97     }
 98 
 99     /**
100      * 普通缓存放入并设置时间
101      * @param key 键
102      * @param value 值
103      * @param time 时间(秒) time要大于0,如果小于或等于0,则设置无期限
104      * @return boolean
105      */
106     public boolean set(String key,Object value,long time){
107         try{
108             if(time>0)
109                 redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
110             else
111                 set(key,value);
112             return true;
113         }catch (Exception e){
114             e.printStackTrace();
115             return false;
116         }
117     }
118 
119     /**
120      * 递增
121      * @param key 键
122      * @param delta 要增加多少
123      * @return
124      */
125     public long incr(String key,long delta){
126         if(delta<0)
127             throw new RuntimeException("递增因子必须大于0");
128         return redisTemplate.opsForValue().increment(key,delta);
129     }
130 
131     /**
132      * 递减
133      * @param key 键
134      * @param delta 要减少多少
135      * @return
136      */
137     public long decr(String key,long delta){
138         if(delta<0)
139             throw new RuntimeException("递减因子必须大于0");
140         return redisTemplate.opsForValue().decrement(key,delta);
141     }
142 
143     //=====================================Map============================
144     /**
145      * HashGet
146      * @param key 键 不能为null
147      * @param item 项 不能为null
148      * @return149      */
150     public Object hget(String key,String item){
151         return redisTemplate.opsForHash().get(key,item);
152     }
153 
154     /**
155      * 获取hashKey对应的所有键值
156      * @param key 键
157      * @return 对应的多个键值
158      */
159     public Map<Object,Object> hmget(String key){
160         return redisTemplate.opsForHash().entries(key);
161     }
162 
163     /**
164      * HashSet
165      * @param key 键
166      * @param map 对应多个键值
167      * @return boolean
168      */
169     public boolean hmset(String key,Map<String,Object> map){
170         try{
171             redisTemplate.opsForHash().putAll(key,map);
172             return true;
173         }catch (Exception e){
174             e.printStackTrace();
175             return false;
176         }
177     }
178 
179     /**
180      * HashSet 并设置时间
181      * @param key 键
182      * @param map 多个键值对
183      * @param time 时间(秒)
184      * @return boolean
185      */
186     public boolean hmset(String key,Map<String,Object> map,long time){
187         try{
188             redisTemplate.opsForHash().putAll(key,map);
189             if(time>0)
190                 expire(key,time);  //如果时间大于0,设置这个键中的数据保存时长为time秒
191             return true;
192         }catch (Exception e){
193             e.printStackTrace();
194             return false;
195         }
196     }
197 
198     /**
199      * 向一张hash表中放入数据,如果不存在将创建
200      * @param key 键
201      * @param item 项
202      * @param value 值
203      * @return boolean
204      */
205     public boolean hset(String key,String item,Object value){
206         try{
207             redisTemplate.opsForHash().put(key,item,value);
208             return true;
209         }catch (Exception e){
210             e.printStackTrace();
211             return false;
212         }
213     }
214 
215     /**
216      * 向一张hash表中放入数据,如果不存在将创建并设置表的时间
217      * @param key 键
218      * @param item 项
219      * @param value 值
220      * @param time 时间(秒), 如果已存在的hash表有时间,则会替代原有的时间
221      * @return boolean
222      */
223     public boolean hset(String key,String item,Object value,long time){
224         try{
225             redisTemplate.opsForHash().put(key,item,value);
226             if(time>0)
227                 expire(key,time);
228             return true;
229         }catch (Exception e){
230             e.printStackTrace();
231             return false;
232         }
233     }
234 
235     /**
236      * 删除hash表中的值
237      * @param key 键 不能为null
238      * @param item 项 可以是多个,不能为Null
239      */
240     public void hdel(String key,Object... item){
241         redisTemplate.opsForHash().delete(key,item);
242     }
243 
244     /**
245      * 判断hash表中是否有该项的值
246      * @param key 键 不能为null
247      * @param item 项 不能为Null
248      * @return
249      */
250     public boolean hHasKey(String key,String item){
251         return redisTemplate.opsForHash().hasKey(key,item);
252     }
253 
254     /**
255      * hash递增 如果不存在,就创建一个 并把新增后的值返回
256      * @param key 键
257      * @param item 项
258      * @param delta 增加多少
259      * @return
260      */
261     public double hincr(String key,String item,double delta){
262         if (delta<0)
263             return delta;
264         else
265             return redisTemplate.opsForHash().increment(key,item,delta);
266     }
267 
268     /**
269      * hash递减
270      * @param key
271      * @param item
272      * @param delta
273      */
274     public double hdecr(String key,String item,double delta){
275         if (delta<0)
276             return delta;
277         else
278             return redisTemplate.opsForHash().increment(key,item,-delta);
279     }
280 
281     //=================================set==============================
282     /**
283      * 根据key获取set中的值
284      * @param key
285      * @return
286      */
287     public Set<Object> sget(String key){
288         try{
289             return redisTemplate.opsForSet().members(key);
290         }catch (Exception e){
291             e.printStackTrace();
292             return null;
293         }
294     }
295 
296     /**
297      * 根据value从一个set中查询,是否存在
298      * @param key
299      * @param value
300      * @return
301      */
302     public boolean sHasKey(String key,Object value){
303         try{
304             return redisTemplate.opsForSet().isMember(key,value);
305         }catch (Exception e){
306             e.printStackTrace();
307             return false;
308         }
309     }
310 
311     /**
312      * 将数据放入set缓存
313      * @param key 键
314      * @param values 值 可以是多个
315      * @return 成功个数
316      */
317     public long sSet(String key,Object... values){
318         try{
319             return redisTemplate.opsForSet().add(key,values);
320         }catch (Exception e){
321             e.printStackTrace();
322             return 0;
323         }
324     }
325 
326     /**
327      * 将set数据放入缓存
328      * @param key 键
329      * @param time 时间
330      * @param values 值 可以是多个
331      * @return
332      */
333     public long sSet(String key,long time,Object... values){
334         try {
335             Long count = redisTemplate.opsForSet().add(key,values);
336             if(time>0)
337                 expire(key,time);
338             return count;
339         }catch (Exception e){
340             e.printStackTrace();
341             return 0;
342         }
343     }
344 
345     /**
346      * 获取set缓存的长度
347      * @param key
348      * @return
349      */
350     public long sGetSetSize(String key){
351         try{
352             return redisTemplate.opsForSet().size(key);
353         }catch (Exception e){
354             e.printStackTrace();
355             return 0;
356         }
357     }
358 
359     /**
360      * 移除值为value的
361      * @param key
362      * @param values 值 可以是多个
363      * @return
364      */
365     public long setRemove(String key,Object... values){
366         try{
367             long count = redisTemplate.opsForSet().remove(key,values);
368             return count;
369         }catch (Exception e){
370             e.printStackTrace();
371             return 0;
372         }
373     }
374 
375     //===============================List===============================
376 
377     /**
378      * 获取list缓存的内容
379      * @param key 键
380      * @param start 开始
381      * @param end 结束 0到-1代表所有值
382      */
383     public List<Object> lGet(String key,long start,long end){
384         try{
385             return redisTemplate.opsForList().range(key,start,end);
386         }catch (Exception E){
387             E.printStackTrace();
388             return null;
389         }
390     }
391 
392     /**
393      * 获取list缓存的长度
394      * @param key
395      * @return long
396      */
397     public long lGetSize(String key){
398         try{
399             return redisTemplate.opsForList().size(key);
400         }catch (Exception e){
401             e.printStackTrace();
402             return 0;
403         }
404     }
405 
406     /**
407      * 通过索引 获取list的值
408      * @param key
409      * @param index 索引 index>=0时,0表头,1第二个元素 index<0时 -1表尾 -2倒数第二个
410      */
411     public Object lGetIndex(String key,long index){
412         try{
413             return redisTemplate.opsForList().index(key,index);
414         }catch (Exception e){
415             e.printStackTrace();
416             return null;
417         }
418     }
419 
420     /**
421      * 将键值对放入list缓存
422      * @param key 键
423      * @param value 值
424      */
425     public boolean lSet(String key,Object value){
426         try{
427             redisTemplate.opsForList().rightPush(key,value);
428             return true;
429         }catch (Exception e){
430             e.printStackTrace();
431             return false;
432         }
433     }
434 
435     /**
436      * 将list放入缓存
437      * @param key
438      * @param value
439      */
440     public boolean lSet(String key,List<Object> value){
441         try{
442             redisTemplate.opsForList().rightPushAll(key,value);
443             return true;
444         }catch (Exception e){
445             e.printStackTrace();
446             return false;
447         }
448     }
449 
450     /**
451      * 将list放入缓存
452      * @param key 键
453      * @param value 值
454      * @param time 时间(秒)
455      */
456     public boolean lSet(String key,List<Object> value,long time){
457         try{
458             redisTemplate.opsForList().rightPushAll(key,value);
459             if(time>0)
460                 expire(key,time);
461             return true;
462         }catch (Exception e){
463             e.printStackTrace();
464             return false;
465         }
466     }
467 
468     /**
469      * 根据索引修改list中的某条数据
470      * @param key 键
471      * @param index
472      * @param value
473      */
474     public boolean lUpdateIndex(String key,long index,Object value){
475         try{
476             redisTemplate.opsForList().set(key,index,value);
477             return true;
478         }catch (Exception e){
479             e.printStackTrace();
480             return false;
481         }
482     }
483 
484     /**
485      * 移除N个值为value
486      * @param key
487      * @param count
488      * @param value
489      * @return 移除的个数
490      */
491     public long lRemove(String key,long count,Object value){
492         try{
493             long remove = redisTemplate.opsForList().remove(key,count,value);
494             return remove;
495         }catch (Exception e){
496             e.printStackTrace();
497             return 0;
498         }
499     }
500 }

 

测试一下其中的一些方法:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@WebAppConfiguration
public class SpringbootApplicationTests {
    @Autowired
    private RedisUtil redisUtil;

    @Test
    public void contextLoads() {
//        Category category = new Category();
//        category.setId(1);
//        category.setName("lala");
//        redisUtil.lSet("list",category);
        Category c = (Category)redisUtil.lGetIndex("list",2);
        System.out.println(c);
    }
}

这里先是将Category类通过lSet()方法保存到Redis中,其键位"list"

然后通过lGetIndex()方法,获取这个对象,并强转为Category,从而获得结果

Category[id=1,name=lala]

当然也可以通过Redis客户端,检查是否有这个数据

127.0.0.1:6379> lrange list 0 3
1) "\\"redis\\""
2) "\\"redis\\""
3) "[\\"com.springboottest.springboot.pojo.Category\\",{\\"id\\":1,\\"name\\":\\"lala\\"}]"

 

参考:http://www.cnblogs.com/ashleyboy/p/9595584.html

StringRedisTemplate是Spring Boot内置的操作Redis的API实现类,另外还有一个API实现类是RedisTemplate。StringRedisTemplate的API假定所有的数据类型化都是字符类型,即key和value都是字符串类型,对于常见额SpringBoot应用系统,使用字符串操作也已经足够了,而且能方便的通过客户端管理工具管理。StringRedisTemplate继承RedisTemplate,与RedisTemplate不同的是重新设置了序列化策略,使用StringRedisSerialier类来序列化key-value,包括List、Hash、Set等数据结构。

 

_________________________________________________________________________________________

除了使用Redis模板进行缓存外,还可以通过指定Spring Cache缓存支持,通过注解进行缓存

 

六.自定义CacheManager

通过配置Spring的CacheManager为Redis,来指定Redis做缓存

构造RedisCacheManager的方法有两种

一种是静态方法create获得 Spring默认配置的CacheManager

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
    RedisCacheManager cacheManager = RedisCacheManager.create(factory);
    return cacheManager;
}

另一种是通过RedisCacheManager构建器→builder(factory)方法,进行自定义配置后获得

RedisCacheManager cacheManager = RedisCacheManager.builder(factory) 
                .initialCacheNames(cacheNames)
                .withInitialCacheConfigurations(configmap) 
                .build();

 此处给出完整代码:

    @Bean
public CacheManager cacheManager(RedisConnectionFactory factory){
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
//生成一个默认配置,通过config对象即可对缓存进行自定义配置
config = config.entryTtl(Duration.ofMinutes(1)) //通过Duration,设置缓存的过期时间为1分钟
.disableCachingNullValues()//不缓存空值
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))//设置key序列化器
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));//设置value序列化器


RedisCacheManager cacheManager = RedisCacheManager.builder(factory) //使用自定义的缓存配置初始化cacheManager
.cacheDefaults(config)
.build();
//RedisCacheManager redisCacheManager = RedisCacheManager.create(factory);
return cacheManager;
}
    private RedisSerializer<String> keySerializer(){
        return new StringRedisSerializer();
    }

    private RedisSerializer<Object> valueSerializer(){
        return new Jackson2JsonRedisSerializer(Object.class);
    }

 

七.在SpringBoot的主程序中加入@EnableCaching开启缓存

@SpringBootApplication
@EnableCaching
public class SpringbootApplication  {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

 

以下为操作示例:

八.准备一个实体类,Mapper和Service

1.实体类

package com.springboottest.springboot.pojo;

public class Person {
    private long id;
    private String name;
    private long age;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getAge() {
        return age;
    }

    public void setAge(long age) {
        this.age = age;
    }

    @Override
    public String toString(){
        return "Person[id="+id+",name="+name+",age="+age+"]";
    }
}

2.Mapper

@Mapper
@Component("personmapper")
public interface PersonMapper {

    @Insert("insert into person_ (name,age) values(#{name},#{age})")
    public int add(Person person);

    @Select("select * from person_ where id = #{id}")
    public Person get(long id);

}

3.Service

@Service
@CacheConfig(cacheNames = "person")
public class PersonService {
    @Autowired
    private PersonMapper personMapper;

    @Cacheable(cacheNames = "person1" ,key="#root.methodName+‘[‘+#id+‘]‘")
    public Person getPersonById(long id){
        Person person = personMapper.get(id);
        return person;
    }

}

 

九.准备 person_表

create table blood_(
id BIGINT(11) PRIMARY key auto_increment,
name VARCHAR(30) not null,
age BIGINT(11) not null
)ENGINE=INNODB

本人数据库学得不好....这里就随便写的数据建的

 

十.调用service中的getPersonById

通过调用service中的getPersonById, 从数据库中获得Person的数据, 然后Spring框架会自动缓存数据到Redis中

这里我用RedisClient界面查看的数据

技术图片

技术图片

可以看到缓存后,保存到了Redis中的person1下

key为person1::getPersonBtId[1]

value为保存在数据库中的数值

 

以上是关于Redis-SpringBoot整合(注解和模板)的主要内容,如果未能解决你的问题,请参考以下文章

Java开发Spring之IOC详解第二篇(注解开发JdbcTemplatem模板Junit整合)

SSH框架的基本整合

SSH框架的基本整合

Spring框架学习spring整合hibernate

spring整合struts2

SSH整合步骤之注解和非注解