新建个目录mkdir njl
在njl目录下安装redis包
安装下载包
wget http://download.redis.io/releases/redis-5.0.5.tar.gz
解压这个压缩包
tar -zxf redis-5.0.5.tar.gz
进入redis安装目录
cd redis-5.0.4
进入redis源码目录。
cd src
记得先装下 yum install gcc ,否者会找不到这个命令
问题:
In file included from adlist.c:34:0:
zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录
解决:
make MALLOC=libc
make
make install PREFIX=/usr/local/redis
把安装包里的配置文件,复制一份到/usr/local/redis这个目录里
mv redis.conf /usr/local/redis
修改配置文件 redis.conf
bing 绑定改为 0.0.0.0 任意机器都可以访问
requirepass 设置密码
将daemonize属性改为yes(表明需要在后台运行)
启动redis命令 ./redis-server ../redis.conf
进入客户端命令 ./redis-cli -p 端口号 -a 密码
auth 密码
可以使用redis安装包里的utils,install_server.sh
选择路径 都选择/usr/local/redis/redis.conf
/usr/local/redis/redis.log
/usr/local/redis/data
/usr/local/redis/bin/redis-server
停止redis进程
systemctl stop redis_6379
重新启动redis进程
systemctl start redis_6379
开放防火墙端口号
firewall-cmd --add-port=6379/tcp --permanent
刷新防火墙:firewall-cmd --reload
可以安装一个客户端,下载redis-desktop,直接安装到本地电脑
链接:https://pan.baidu.com/s/13C8SZUQbw98WzL2UOzWjZA
提取码:yqcy
通用缓存key封装
接口
抽象类
实现类
验证是否安装使用
springboot集成redis
这块不使用了提供的客户端了redistemplate,依赖原生的Jedis,自己写一个。
知识点,序列化。序列化这块使用Fastjson,使用fastjson把java对象转换成字符串写到redis服务器里面去。序列化最快的使用谷歌的Google protobuf,但是它序列化之后不可读的,是二进制格式的。但是使用Fastjson序列化后,是json格式,是明文可读的。效率能差一倍。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.38</version>
</dependency>
然后配置redis
#redis
redis.host=xx.xx.xx.xxx
redis.port=6379
#redis超时时间
redis.timeout=3
redis.password=xxxxxx
#redis也是使用连接池
#redis最大连接数
redis.poolMaxTotal=10
#redis最大空闲连接数
redis.poolMaxIdle=10
#redis最大等待连接数
redis.poolMaxWait=3
第一步,先创建一个redis的配置类RedisConfig,使用@Component注解,把这个类注入到spring容器中,之前文章介绍过这个,如果大家没有印象,可以看下之前的文章。读取配置文件里的配置,带上prefix=“redis”,代表只要有redis前缀的都读取出来。@Data这个注解是使用lombok这个包,加上这个注解,相当于不用写get、set方法了,比较省事。
@Component
@ConfigurationProperties(prefix = "redis")
@Data
public class RedisConfig {
private String host;
private int port;
private int timeout;//秒
private String password;
private int poolMaxTotal;
private int poolMaxIdle;
private int poolMaxWait;//秒
}
第二步我们写一个RedisService这个类,如果使用原生的jedis,我们看下官方文档,https://github.com/xetorthio/jedis,它是这么用的To use it just:
Jedis jedis = new Jedis("localhost");
jedis.set("foo", "bar");
String value = jedis.get("foo");
现在就是想办法建出一个jedis这么一个类,刚才说了我们使用的连接池。
@Service
publice class RedisService{
@Autowire
JedisPool jedisPool;
public <T>T get(String key ,Class<T> clazz){
Jedis jedis=null;
try{
jedis = jedisPool.getResource();
String str =jedis.get(key);
return stringToBean(str,clazz);
}catch(Exception e){
e.println();
}finally{
returnToPool(jedis);
}
}
public <T>boolean set(String key ,T value){
Jedis jedis=null;
try{
jedis=jedisPool.getResource();
String val =beanToString(value);
jedis.set(key,val);
return true;
}catch(Exception e){
e.println();
}finally{
returnToPool(jedis);
}
}
private <T>T stringToBean(String str,Class<T> clazz){
if(str==null||str.length()<=0||clazz==null){
return null;
}
if(clazz ==int.class||clazz==Ingeter.class){
return (T)Integer.valueOf(str);
}else if(clazz==long.class||clazz=Long.class){
return (T)Long.valueOf(str);
}else if(clazz ==String.class){
return (T)str
}else{
return JSON.toJavaObject(JSON.parseObject(str),clazz);
}
}
private <T>String beanToString(T value){
//这块加点判断,如果value是int类型或者long类型,不是字符串
if(value ==null){
return null;
}
Class<?> clazz=value.getClass();
if(clazz ==int.class||class ==Integer.class){
return value;
}else if(clazz == long.class||clazz ==Long.class){
return value;
}else if(clazz ==String.class){
return (String)valule;
}else{
return JSON.toJSONString(value);
}
}
private void JedisPool returnToPool(Jedis jedis){
if(jedis!=null){
jedis.close();
}
}
}
新建一个RedisPoolFactory类,如果有不懂的地方,就点进去看源码,redis默认16个库,如果不指定,就是从0开始的。这块我们也默认从0开始吧,所以传入个0.
@Configuration
public class RedisPoolFactory(){
@Autowire
RedisConfig redisConfig
@Bean
public JedisPool jedisPool(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotle(redisConfig.getPoolMaxTotal());
jedisPoolConfig.setMaxIdle(redisConfig.getPoolMaxIdle();
jedisPoolConfgi.setMaxWait(redisConfig.getPoolMaxWait()*1000);
JedisPool jp = new JedisPool(jedisPoolConfig,redisConfig.getHost(),redisConfig.getPort,redisConfig.getPassword(),redisConfig.getTimeout()*1000,0);
retrun jp;
}
}
第三步我们在Controller类中 ,注入RedisService这个类。
@Controller
@RequestMapping("/redis")
public class DemoController{
@Autowired
RedisService redisService
@RequestMapping("/get")
@ResponseBody
public Result<String> get(){
String value=redisService.get("key2",String.class);
return Result.success(value);
}
@RequestMapping("/set")
@ResponseBody
public Result<Boolean> set(){
Boolean bl=redisService.set("key2","hello,redis");
return Result.success(bl);
}
)
看下我们服务器的redis里是否存进去
有了 说明正确。
但是这么做还是不够完美,因为入参都是字符串常量,多人开发容易导致,key重复。为了解决这个我们采用加个前缀入参,例如可以代表用户模块、这个前缀就是用户,用于订单模块这个前缀就是订单,然后用前缀+key,作为真正的存到redis里的key,这样就可以避免重复key出现。我们写一个通用的封装结构接口->抽象类->实现类,接口定义一些契约、抽象类可以实现共同的实现,把特殊的实现留给子类实现。
那么接下了我们先创建一个接口类
public interface KeyPrefix{
//有效期
public int expireSecond();
public String getPrefix();
}
然后写一个抽象实现类
public abstract class BasePrefix implements KeyPrefix{
private int expireSeconds;
private String prefix;
//没有过期时间的,代表永不过期
public BasePrefix(String prefix){
this(0,prefix);
}
public BasePrefix(int expireSeconds,String prefix){
this.expireSeconds=expireSeconds;
this.prefix= prefix;
}
public int expireSecond(){
return expireSeconds;
}
public String getPrefix(){
String className =getClass().getSimpleName();
String key =className+":"+prefix;
}
}
在写一个类继承这个抽象的实现类,比如可以是订单模块、用户模块
public class UserKey extends BasePrefix{
private UserKey(String prefix){
super(prefix);
}
//成员变量
public static UserKey getById = new UserKey("id");
public static UserKey getByName = new UserKey("name");
}
所以之后的controller也要改一下,就是增加一个参数
@Controller
@RequestMapping("/redis")
public class DemoController{
@Autowired
RedisService redisService
@RequestMapping("/get")
@ResponseBody
public Result<User> get(){
User user=redisService.get(UserKey.getById,"key2",User.class);
return Result.success(user);
}
@RequestMapping("/set")
@ResponseBody
public Result<Boolean> set(){
User user = new User();
user.setId(1111);
user.setName("不知道");
Boolean bl=redisService.set(UserKey.getById,1,user);
return Result.success(bl);
}
)
然后我们的service层里的get和set方法也要改一下
@Service
publice class RedisService{
@Autowire
JedisPool jedisPool;
public <T>T get(KeyPrefix keyPrefix ,String key ,Class<T> clazz){
Jedis jedis=null;
try{
jedis = jedisPool.getResource();
String realKey = keyPrefix.getPrefix()+key;
String str =jedis.get(realKey);
return stringToBean(str,clazz);
}catch(Exception e){
e.println();
}finally{
returnToPool(jedis);
}
}
public <T>boolean set(KeyPrefix keyPrefix,String key ,T value){
Jedis jedis=null;
try{
jedis=jedisPool.getResource();
String realKey=keyPrefix.getPrefix()+key;
//有效期
Int expireSeconds=keyPrefix.expireSeconds();
String val =beanToString(value);
if(expireSeconds<=0){}
jedis.set(realKey,val);
}else{
jedis.setex(realkey,expireSeconds,val);
}
return true;
}catch(Exception e){
e.println();
}finally{
returnToPool(jedis);
}
}
private <T>T stringToBean(String str,Class<T> clazz){
if(str==null||str.length()<=0||clazz==null){
return null;
}
if(clazz ==int.class||clazz==Ingeter.class){
return (T)Integer.valueOf(str);
}else if(clazz==long.class||clazz=Long.class){
return (T)Long.valueOf(str);
}else if(clazz ==String.class){
return (T)str
}else{
return JSON.toJavaObject(JSON.parseObject(str),clazz);
}
}
private <T>String beanToString(T value){
//这块加点判断,如果value是int类型或者long类型,不是字符串
if(value ==null){
return null;
}
Class<?> clazz=value.getClass();
if(clazz ==int.class||class ==Integer.class){
return value;
}else if(clazz == long.class||clazz ==Long.class){
return value;
}else if(clazz ==String.class){
return (String)valule;
}else{
return JSON.toJSONString(value);
}
}
private void JedisPool returnToPool(Jedis jedis){
if(jedis!=null){
jedis.close();
}
}
}