【SpringBoot】结合Redis实现缓存
Redis经常用于缓存。接下来,我们以Springboot框架为例。实现一些Redis的基础操作,创建完SpingBoot项目后,具体步骤如下图:
pom中添加项目依赖
<!-- Redis 缓存--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.5.15</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>2.5.12</version> </dependency>
配置Redis连接
打开配置文件(以application.yml为例)
spring: redis: database: 0 # 数据库索引,默认为0 host: 127.0.0.1 # redis地址 port: 6379 # redis服务器端口地址 # sping.redis.password 表示密码,因为密码为空,这里不设置 jedis: pool: max-wait: 3000 # 连接池最大阻塞等待时间,单位毫秒(使用负值表示没有限制) min-idle: 0 # 连接池最小空闲时间 timeout: 3000 # 连接超时时间(毫秒)
编写Redis配置文件
新建配置文件。这里实现了连接配置工厂和序列化。(需要序列化,否则存储的中文,不可阅读)
1 @Configuration 2 @EnableCaching 3 public class RedisConfig extends CachingConfigurerSupport { 4 5 /** 6 * RedisTemplate相关配置 7 * 使redis支持插入对象 8 * 9 * @param factory 10 * @return 方法缓存 Methods the cache 11 */ 12 @Bean 13 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { 14 RedisTemplate<String, Object> template = new RedisTemplate<>(); 15 // 配置连接工厂 16 template.setConnectionFactory(factory); 17 // 序列化 key 和hashKey采用String序列化;value和hashValue采用JSON序列化 18 GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); 19 template.setKeySerializer(RedisSerializer.string()); 20 template.setHashKeySerializer(RedisSerializer.string()); 21 // value和hashvalue采用JSON序列化 22 template.setValueSerializer(jsonRedisSerializer); 23 template.setHashValueSerializer(jsonRedisSerializer); 24 return template; 25 } 26 }
测试Redis缓存
写入测试方法,发现能够完成Redis的存储与读取。
1 @SpringBootTest 2 public class RedisTest { 3 @Autowired 4 private RedisTemplate redisTemplate; 5 @Autowired 6 private RedisUtils redisUtils; 7 /** 8 * 测试添加String类型 9 * @author lyj 10 * @date 2024-09-28 11 */ 12 @Test 13 public void testAddString(){ 14 String key = "redisTest:user:name"; 15 String value = "张三"; 16 redisTemplate.opsForValue().set(key,value); 17 System.out.println(redisTemplate.opsForValue().get(key)); 18 } 19 /** 20 * 测试添加Object类型 21 * @author lyj 22 * @date 2024-09-28 23 */ 24 @Test 25 public void testAddObject(){ 26 String key = "redisTest:user:1"; 27 SysUser sysUser = new SysUser(); 28 sysUser.setId(1); 29 sysUser.setUsername("林冲"); 30 sysUser.setPassword("123456"); 31 redisTemplate.opsForValue().set(key,sysUser); 32 } 33 34 /** 35 * 测试读取redis 36 * @author lyj 37 * @date 2024-09-28 38 */ 39 @Test 40 public void testGet(){ 41 String key = "redisTest:user:name"; 42 System.out.println( redisTemplate.opsForValue().get(key)); // 张三 43 } 44 }
发现,能够实现类的创建和读取。
创建Redis缓存工具类
上面案例都是直接用RedisTemplate操作Redis。我们可以实现,RedisUtils交给Spring容器实例化,使用时直接注解注入,使用方便简单,减少使用难度。
1 @Component 2 public class RedisUtils { 3 @Autowired 4 private RedisTemplate redisTemplate; 5 6 public RedisUtils(RedisTemplate redisTemplate) { 7 this.redisTemplate = redisTemplate; 8 } 9 //region 基础操作 10 /** 11 * 指定缓存失效时间 12 * @param key 键 13 * @param time 时间(秒) 14 * @return 15 */ 16 public boolean expire(String key,long time){ 17 try { 18 if(time > 0){ 19 redisTemplate.expire(key,time, TimeUnit.SECONDS); 20 } 21 return true; 22 }catch (Exception e){ 23 e.printStackTrace(); 24 return false; 25 } 26 } 27 28 /** 29 * 根据可以获取过期时间 30 * @param key 键(不能为null) 31 * @return 返回单位秒,返回 -1 代表永久有效 32 */ 33 public long getExpire(String key){ 34 return redisTemplate.getExpire(key,TimeUnit.SECONDS); 35 } 36 37 /** 38 * 判断key是否存在 39 * @param key 键 40 * @return 41 */ 42 public boolean hasKey(String key){ 43 try{ 44 return redisTemplate.hasKey(key); 45 }catch (Exception e){ 46 e.printStackTrace(); 47 return false; 48 } 49 } 50 51 /** 52 * 删除1个或多个缓存 53 * @param keys 54 */ 55 public long del(String ...keys){ 56 if(keys != null && keys.length > 0){ 57 if(keys.length ==1){ 58 return redisTemplate.delete(keys[0]) ? 1L:0L; 59 }else { 60 return redisTemplate.delete(CollectionUtils.arrayToList(keys)) ; 61 } 62 } 63 return 0L; 64 } 65 66 /** 67 * 模糊查询获取key值 68 * @param pattern 69 * @return 70 */ 71 public Set keys(String pattern){ 72 return redisTemplate.keys(pattern); 73 } 74 75 /** 76 * 使用redis的消息队列 77 * @param channel 78 * @param message 消息内容 79 */ 80 public void convertAndSend(String channel, Object message){ 81 redisTemplate.convertAndSend(channel,message); 82 } 83 //endregion 84 //region String 85 86 /** 87 * 获取普通缓存获取 88 * @param key 键 89 * @return 值 90 */ 91 public Object get(String key){ 92 return key == null? null: redisTemplate.opsForValue().get(key); 93 } 94 95 /** 96 * 设置普通缓存 97 * @param key 键 98 * @param value 值 99 * @return 100 */ 101 public boolean set(String key, Object value){ 102 try{ 103 redisTemplate.opsForValue().set(key,value); 104 return true; 105 }catch (Exception e){ 106 e.printStackTrace(); 107 return false; 108 } 109 } 110 111 /** 112 * 设置缓存放入,并设置时间 113 * @param key 键 114 * @param value 值 115 * @param time 时间秒(time值小于0,怎设置无限期) 116 * @return 117 */ 118 public boolean set(String key,Object value, long time){ 119 try{ 120 if(time > 0){ 121 redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS); 122 }else { 123 redisTemplate.opsForValue().set(key,value); 124 } 125 return true; 126 }catch (Exception e){ 127 e.printStackTrace(); 128 return false; 129 } 130 } 131 132 /** 133 * 递增 134 * @param key 键 135 * @param delta 要增加的值 136 * @return 137 */ 138 public long incr(String key,long delta){ 139 if(delta < 0){ 140 throw new RuntimeException("递增因子,必须大于0"); 141 } 142 return redisTemplate.opsForValue().increment(key,delta); 143 } 144 145 /** 146 * 递减 147 * @param key 键 148 * @param delta 要减小的值 149 * @return 150 */ 151 public long descr(String key ,long delta){ 152 if(delta < 0){ 153 throw new RuntimeException("递减因子,必须大于0"); 154 } 155 return redisTemplate.opsForValue().increment(key,-delta); 156 } 157 //endregion 158 //region hash 159 /** 160 * 向一张hash表中放入数据,如果不存在将创建 161 * @param key 键 162 * @param item 项 163 * @param value 值 164 * @return 165 */ 166 public boolean hset(String key, String item, Object value){ 167 try{ 168 redisTemplate.opsForHash().put(key,item,value); 169 }catch (Exception e){ 170 e.printStackTrace(); 171 return false; 172 } 173 return true; 174 } 175 176 /** 177 * 向一张表中放入数据,如果不存在,则创建 178 * @param key 键 179 * @param item 项 180 * @param value 值 181 * @param time 时间(秒),如果已存在的hash表有时间,这里将会替换原有的时间 182 * @return 183 */ 184 public boolean hset(String key, String item, Object value, long time){ 185 try{ 186 redisTemplate.opsForHash().put(key,item,value); 187 if(time > 0){ 188 redisTemplate.expire(key,time, TimeUnit.SECONDS); 189 } 190 }catch (Exception e){ 191 e.printStackTrace(); 192 return false; 193 } 194 return true; 195 } 196 197 /** 198 * 删除hash表中的值 199 * @param key 键 200 * @param items 项,可以多个,不能为空 201 */ 202 public void hdel(String key, Object ...items){ 203 redisTemplate.opsForHash().delete(key, items); 204 } 205 206 /** 207 * 获取Hash值 208 * @param key 键,不能为空 209 * @param item 项目不能为空 210 * @return 211 */ 212 public Object hget(String key, String item){ 213 return redisTemplate.opsForHash().get(key,item); 214 } 215 216 /** 217 * 获取HashKey的所有键值 218 * @param key 键 219 * @return 220 */ 221 public Map<Object,Object> hmget(String key){ 222 return redisTemplate.opsForHash().entries(key); 223 } 224 /** 225 * 设置HashKey的所有键值 226 * @param key 键 227 * @param map 对应多个键值 228 * @return 229 */ 230 public boolean hmset(String key, Map<String , Object> map){ 231 try { 232 redisTemplate.opsForHash().putAll(key,map); 233 }catch (Exception e){ 234 e.printStackTrace(); 235 return false; 236 } 237 return true; 238 } 239 240 /** 241 * HashSet 并设置时间 242 * @param key 键 243 * @param map 对应多个键值 244 * @param time 时间(秒) 245 * @return 246 */ 247 public boolean hmset(String key, Map<String , Object> map,long time){ 248 try { 249 redisTemplate.opsForHash().putAll(key,map); 250 if(time > 0){ 251 redisTemplate.expire(key,time,TimeUnit.SECONDS); 252 } 253 }catch (Exception e){ 254 e.printStackTrace(); 255 return false; 256 } 257 return true; 258 } 259 260 /** 261 * 判断hash表中是否有该项值 262 * @param key 键,不能为空 263 * @param item 项,不能为空 264 * @return 265 */ 266 public boolean hHashKey(String key,String item){ 267 return redisTemplate.opsForHash().hasKey(key,item); 268 } 269 270 /** 271 * hash递增,如果不存在就会创建一个,并把新增后的值返回 272 * @param key 键 273 * @param item 项 274 * @param by 要增大几(大于0) 275 * @return 276 */ 277 public double hinc(String key, String item, double by){ 278 return redisTemplate.opsForHash().increment(key,item,by); 279 } 280 281 /** 282 * hash递减 283 * @param key 键 284 * @param item 项 285 * @param by 要减小几(大于0) 286 * @return 287 */ 288 public double hdescr(String key, String item, double by){ 289 return redisTemplate.opsForHash().increment(key,item,-by); 290 } 291 //endregion 292 //region set 293 /** 294 * 根据key,获取set的所有值 295 * @param key 键 296 * @return 297 */ 298 public Set<Object> sGet(String key){ 299 try { 300 return redisTemplate.opsForSet().members(key); 301 }catch (Exception e){ 302 e.printStackTrace(); 303 return null; 304 } 305 } 306 307 /** 308 * 根据value一个set查询,是否存在 309 * @param key 键 310 * @param value 值 311 * @return 312 */ 313 public boolean sHashKey(String key, Object value){ 314 try { 315 return redisTemplate.opsForSet().isMember(key,value); 316 }catch (Exception e){ 317 e.printStackTrace(); 318 return false; 319 } 320 } 321 322 /** 323 * 将数据放入set缓存 324 * @param key 键 325 * @param values 值,可以时多个 326 * @return 327 */ 328 public long sSet(String key, Object... values){ 329 try { 330 return redisTemplate.opsForSet().add(key,values); 331 }catch (Exception e){ 332 e.printStackTrace(); 333 return 0; 334 } 335 } 336 /** 337 * 将数据放入set缓存,并设置时间 338 * @param key 键 339 * @param time 时间(秒) 340 * @param values 值,可以时多个 341 * @return 342 */ 343 public long sSetAndTime(String key,long time, Object... values){ 344 try { 345 long count = redisTemplate.opsForSet().add(key,values); 346 if(time > 0){ 347 redisTemplate.expire(key,time,TimeUnit.SECONDS); 348 } 349 return count; 350 }catch (Exception e){ 351 e.printStackTrace(); 352 return 0; 353 } 354 } 355 356 /*** 357 * 获取Set缓存长度 358 * @param key 359 * @return 360 */ 361 public long sGetSetSize(String key){ 362 try { 363 return redisTemplate.opsForSet().size(key); 364 }catch (Exception e){ 365 e.printStackTrace(); 366 return 0; 367 } 368 } 369 370 /** 371 * 移除值为value的缓存 372 * @param key 373 * @param values 374 * @return 375 */ 376 public long setRemove(String key, Object ... values){ 377 try { 378 return redisTemplate.opsForSet().remove(key,values); 379 }catch (Exception e){ 380 e.printStackTrace(); 381 return 0; 382 } 383 } 384 //endregion 385 //region list 386 387 /** 388 * 获取list 缓存内容 389 * @param key 键 390 * @param start 开始位置 391 * @param end 结束位置 0 到-1代表所有值 392 * @return 393 */ 394 public List<Object> lGet(String key, long start, long end){ 395 try { 396 return redisTemplate.opsForList().range(key,start,end); 397 }catch (Exception e){ 398 e.printStackTrace(); 399 return null; 400 } 401 } 402 403 /** 404 * 获取list缓存长度 405 * @param key 键 406 * @return 407 */ 408 public long lGetListSize(String key){ 409 try{ 410 return redisTemplate.opsForList().size(key); 411 }catch (Exception e){ 412 e.printStackTrace(); 413 return 0; 414 } 415 } 416 417 /** 418 * 通过索引获取list的值 419 * @param key 键 420 * @param index 索引(> 0,索引),-1表尾,-2倒数第二个元素,以此类推 421 * @return 422 */ 423 public Object lGetIndex(String key,long index){ 424 try{ 425 return redisTemplate.opsForList().index(key,index); 426 }catch (Exception e){ 427 e.printStackTrace(); 428 return null; 429 } 430 } 431 432 /** 433 * 将list缓存 434 * @param key 键 435 * @param value 值 436 * @return 437 */ 438 public long lSet(String key, Object value){ 439 try{ 440 return redisTemplate.opsForList().rightPush(key,value); 441 }catch (Exception e){ 442 e.printStackTrace(); 443 return 0; 444 } 445 } 446 447 /** 448 * 将list缓存,并设置时间 449 * @param key 键 450 * @param value 值 451 * @param time 时间(秒) 452 * @return 453 */ 454 public long lSet(String key, Object value, long time){ 455 try{ 456 long result = redisTemplate.opsForList().rightPush(key,value); 457 if(time > 0){ 458 redisTemplate.expire(key,time,TimeUnit.SECONDS); 459 } 460 return result; 461 }catch (Exception e){ 462 e.printStackTrace(); 463 return 0; 464 } 465 } 466 467 /** 468 * 将list放入缓存 469 * @param key 键 470 * @param value 值 471 * @return 472 */ 473 public long lSet(String key, List<Object> value){ 474 try{ 475 return redisTemplate.opsForList().rightPushAll(key,value); 476 }catch (Exception e){ 477 e.printStackTrace(); 478 return 0; 479 } 480 } 481 482 /** 483 * 将list放入缓存 484 * @param key 键 485 * @param value 值 486 * @param time 时间(秒) 487 * @return 488 */ 489 public long lSet(String key, List<Object> value,long time){ 490 try{ 491 long result = redisTemplate.opsForList().rightPushAll(key,value); 492 if(time > 0){ 493 redisTemplate.expire(key,time,TimeUnit.SECONDS); 494 } 495 return result; 496 }catch (Exception e){ 497 e.printStackTrace(); 498 return 0; 499 } 500 } 501 502 /** 503 * 根据索引修改list的某条数据 504 * @param key 键 505 * @param index 索引 506 * @param value 值 507 * @return 508 */ 509 public boolean lUpdateIndex(String key,long index, Object value){ 510 try{ 511 redisTemplate.opsForList().set(key,index,value); 512 return true; 513 }catch (Exception e){ 514 e.printStackTrace(); 515 return false; 516 } 517 } 518 519 /** 520 * 移除N个值为value 521 * @param key 键 522 * @param count 移除多少个 523 * @param value 值 524 * @return 525 */ 526 public long lRemove(String key, long count, String value){ 527 try { 528 return redisTemplate.opsForList().remove(key,count,value); 529 }catch (Exception e){ 530 e.printStackTrace(); 531 return 0; 532 } 533 } 534 // endregion 535 }
有志者,事竟成,破釜沉舟,百二秦关终属楚; 苦心人,天不负,卧薪尝胆,三千越甲可吞吴。