redis作为炙手可热的缓存中间件,在越来越多的场景使用到,特别是应对高并发业务时,能有效减少数据库访问压力,提高系统抗压能力。利用它丰富的数据类型还可以用来做消息队列、活动排行或计数 、、
全文概要:
2、jedis客户端实现redis的set和get操作
a、读取redis配置文件,封装RedisConfig类
b、创建JedisPoolConfig对象,设置资源池属性(RedisConfig中获取)
c、创建JedisPool对象,调用其getResource方法或得Jedis对象
d、调用jedis.set()、jedis.get()
3、按不同业务模块封装redis中的key
(我们希望对象类型不同,它的键就要相应的前缀。容易想到用接口类型去接收实现类,)
a、定义接口 KeyPrefix
b、抽象类 BasePrefix
c、实现类 UserKey
正文内容:
一、引入依赖
jedis客户端与alibaba fastjson依赖
<!--redis客户端依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--json和对象格式转换-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.38</version>
</dependency>
二、添加redis的配置信息
可以看到使用了资源池,需要先创建JedisPool,再从中获取redis连接客户端。
三、写个配置类读取application.properties中redis配置信息
之前我写的springboot集成mybatis不是没写配置类吗?
因为springboot框架帮我们自动配置了,如何你使用的是RedisTemplate也是自动配置的。
创建redis配置类RedisConfig
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix="redis")
public class RedisConfig {
private String host;
private int port;
private int timeout;//秒
private String password;
private int poolMaxTotal;
private int poolMaxIdle;
private int poolMaxWait;//秒
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPoolMaxTotal() {
return poolMaxTotal;
}
public void setPoolMaxTotal(int poolMaxTotal) {
this.poolMaxTotal = poolMaxTotal;
}
public int getPoolMaxIdle() {
return poolMaxIdle;
}
public void setPoolMaxIdle(int poolMaxIdle) {
this.poolMaxIdle = poolMaxIdle;
}
public int getPoolMaxWait() {
return poolMaxWait;
}
public void setPoolMaxWait(int poolMaxWait) {
this.poolMaxWait = poolMaxWait;
}
}
题外篇
忍不住看了一眼官方配置类,一样的注解指定配置文件中的前缀,五大参数对应的成员变量都可以找到。
四、获取redis客户端对象
1、创建资源池配置类对象(JedisPoolConfig)
2、创建jedisPool对象
五、三层架构写法
准确来说是两层,dao层没有了。自定向下设计,然后自底向上实现。
1、设计思想
需求 ——》 设计接口 ——》服务类 ——》工具类
2、思维过程
第一步:需求
在redis中设置键值对和取出键值对,并且键值是有前缀的。方便区分不同模块,且不同模块间不会覆盖key值。
第二步:设计接口
返回值用Result类封装(成功返回结果,失败返回错误码)
第三步:写服务类
包含两个方法,set与get,两者的入参与返回值是不同的
public <T> boolean set(KeyPrefix prefix,String key, T value){
//实现代码
}
set的入参包括:键的前缀、键、值(任意类型);返回值 boolean
public <T> T get(KeyPrefix prefix,String key, Class<T> clazz) {
//实现代码
}
get入参包括:键的前缀、键、类类型;返回值 对象类型
3、具体代码实现
a、service层实现
package com_item.miaosha.redis;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@Service
public class RedisService {
/**注入RedisFactory中创建的JedisPool对象*/
@Autowired
JedisPool jedisPool;
public <T> T get(KeyPrefix prefix,String key, Class<T> clazz) {
//需要先有jedisPool实例
Jedis jedis = null; //获取jedis客户端
try {
jedis = jedisPool.getResource();
String realKey = prefix.getPrefix()+key;
String str = jedis.get(realKey);
//从redis中拿到的是String类型,需要转为T类型
T t = stringToBean(str, clazz);
return t;
} finally {
returnToPool(jedis);
}
}
/**
* 将对象类型转为字符串写入redis
*/
/**
* @param prefix 是一个接口类型,可以接收UserKey、OrderKey这些实现类
* */
public <T> boolean set(KeyPrefix prefix,String key, T value) {
Jedis jedis = null; //获取jedis客户端
try {
jedis = jedisPool.getResource();
String str = beanToString(value);
if (str == null || str.length() == 0) {
return false;
}
//生成真正的key
//prefix.getPrefix()是接口方法,实际是调用其实现类的方法
String realKey = prefix.getPrefix()+key;
int second = prefix.expireSecond();
if(second <= 0){
jedis.set(realKey, str); //永不过期
}else{
jedis.setex(realKey,second,str);
}
return true;
} finally {
returnToPool(jedis);
}
}
/**
* 将任意类型类型转为字符串
*/
private <T> String beanToString(T value) {
if (value == null) {
return null;
}
//获取value是什么类型,进行判断
Class<?> clazz = value.getClass();
if (clazz == Integer.class || clazz == int.class) {
return "" + value;
} else if (clazz == String.class) {
return (String) value;
} else if (clazz == Long.class || clazz == long.class) {
return "" + value;
} else {
return JSON.toJSONString(value);
}
}
/**
* 将字符串转为Bean对象
*/
private <T> T stringToBean(String str, Class<T> clazz) {
//1、参数校验
if (str == null || str.length() == 0 || clazz == null) {
return null;
}
if (clazz == Integer.class || clazz == int.class) {
return (T) Integer.valueOf(str);
} else if (clazz == String.class) {
return (T) str;
} else if (clazz == Long.class || clazz == long.class) {
return (T) Long.valueOf(str);
} else {
//要求clazz是Bean类型,如果是list,JSON.parseObject(str)不可用
return JSON.toJavaObject(JSON.parseObject(str), clazz);
}
}
//回收不在使用redis客户端
private void returnToPool(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
}
b、controller层实现
package com_item.miaosha.controller;
import com_item.miaosha.redis.RedisService;
import com_item.miaosha.redis.UserKey;
import com_item.miaosha.result.CodeMsg;
import com_item.miaosha.result.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/redis")
@RestController
public class RedisController {
@Autowired
RedisService redisService;
//通过key获取对象
@RequestMapping("/get")
public Result<String> redisGet() {
UserKey userKey = new UserKey(10,"NO");
String value = redisService.get(userKey,""+100,String.class);
if (null == value) { return Result.error(CodeMsg.REDIS_KEY_EMPTY); }
return Result.success(value);
}
//设置key处的对象
@RequestMapping("/set")
public Result<Boolean> redisSet() {
//改进,带前缀的key用来区分不同的模块,避免覆盖
//格式为:类名:+prifix+用户id (例如:UserKey:NO1)
/**创建UserKey类型的键类型,指定过期时间与前缀名*/
UserKey userKey = new UserKey(10,"NO");
redisService.set(userKey,""+100, "xiaoxin");
return Result.success(true);
}
}
六、结果
1、向redis中加入键值对
查看redis发现多了key
2、在redis中获取某个键的值
查看该键的值