一、下载安装
1.下载官网:https://redis.io/download,点击Download 6.2.6,我这里下载的最新的6.2.6版本
2.安装
(1)redis是C语言写的,必须先安装gcc
yum -y install gcc gcc-c++ autoconf pcre pcre-devel make automake
yum -y install wget httpd-tools vim
验证gcc是否成功安装
gcc --version
(2)安装redis
tar xzf redis-6.2.6.tar.gz
cd redis-6.2.6
make
make install
如果此时提示报错”Newer version of jemalloc required“(此时src目录下没有redis-server),执行下面片段
cd deps/
make hiredis jemalloc linenoise lua geohash-int
cd ..
make
make install
(3)启动
./src/redis-server
二、常用配置及使用
(1)redis.conf配置
bind ip地址(可绑定多个)
port 端口
daemonize yes 守护进程运行
protected-mode no 关闭保护模式
requirepass 密码 设置查询密码
(2)进入管理界面(启动后复制会话)
./src/redis-cli -h ip地址 -p 端口(不指定则默认进入127.0.0.1)
./src/redis-cli
(3)常用操作
赋值:
set foo bar
取值:
get foo
查看全部key:keys *
进行赋权(第一步的requirepass 设置):auth 密码
关闭redis:shutdown
清空keys:flushdb
(4)慢日志
实际应用中可能会有redis启动比较耗时的情况,这时候可以设置下慢日志
记录耗时超过一秒的命令:config set slowlog-log-slower-than 1000
保留最近1000条慢日志:config set slowlog-max-len 1000
查看慢日志:slowlog get 5
三、整合SpringBoot
1.首先redis.conf配置记得关闭保护模式和设置密码
服务启动的时候要带上redis.conf,不然配置不会生效
./src/redis-server /redis.conf
2.引入maven库jar包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
3.配置application.yml,注意这里用的自定义的configration,详细见CachePoolProvider.java
redis:
host: 你的ip
port: 6379
password: 你的密码
# redis数据库索引(默认为0)
db: 0
4.导入redis相关的工具类,api参照JedisService.java
CacheManager.java
package com.example.user.utils.redis;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.params.SetParams;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Slf4j
public class CacheManager <T extends Serializable>{
public static JedisPool jedisPool;
public CacheManager() {
}
public boolean save(String namespace, String key, T object, long ttlSeconds) {
key = this.checkAndReturnKey(namespace, key);
if (object == null) {
log.debug("cacheObj for key:{} is null", key);
return false;
} else {
boolean bReturn = false;
Jedis jedis = jedisPool.getResource();
try {
if (ttlSeconds > 0L) {
jedis.setex(key.getBytes("UTF-8"), ttlSeconds, SerializationUtils.serialize(object));
} else {
jedis.set(key.getBytes("UTF-8"), SerializationUtils.serialize(object));
}
bReturn = true;
} catch (UnsupportedEncodingException | JedisConnectionException var12) {
log.error("redis for key: {}", key, var12);
} finally {
if (null != jedis) {
jedis.close();
}
}
return bReturn;
}
}
public boolean remove(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
boolean bReturn = false;
Jedis jedis = jedisPool.getResource();
try {
jedis.del(key.getBytes("UTF-8"));
bReturn = true;
} catch (UnsupportedEncodingException | JedisConnectionException var9) {
log.error("redis for key: {}", key, var9);
} finally {
if (null != jedis) {
jedis.close();
}
}
return bReturn;
}
public T get(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
try {
byte[] bytes = this.getBytes(key);
T obj = bytes != null ? (T) SerializationUtils.deserialize(bytes) : null;
return obj;
} catch (Exception var5) {
log.error("redis for key: {}", key, var5);
}
return null;
}
public boolean exists(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
boolean bReturn = false;
try {
bReturn = jedis.exists(key);
} catch (Exception var9) {
log.error("Error exists key {}:", key, var9);
} finally {
if (null != jedis) {
jedis.close();
}
}
return bReturn;
}
public int lLength(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
int var4 = 0;
try {
var4 = jedis.llen(key).intValue();
} catch (Exception var8) {
log.error("redis for key: {}", key, var8);
} finally {
if (null != jedis) {
jedis.close();
}
}
return var4;
}
public List<String> lRange(String namespace, String key, long start, long end) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
List var9 = new ArrayList();
try {
List<String> result = jedis.lrange(key, start, end);
var9 = result;
} catch (Exception var13) {
log.error("redis for key: {}", key, var13);
} finally {
if (null != jedis) {
jedis.close();
}
}
return var9;
}
public Long rPush(String namespace, String key, String... value) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
Long var6 = 0L;
try {
Long leaveNum = jedis.rpush(key, value);
var6 = leaveNum;
} catch (Exception var10) {
log.error("redis for key: {}", key, var10);
} finally {
if (null != jedis) {
jedis.close();
}
}
return var6;
}
public String lTrim(String namespace, String key, long start, long end) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
String var9 = "";;
try {
String result = jedis.ltrim(key, start, end);
var9 = result;
} catch (Exception var13) {
log.error("redis for key: {}", key, var13);
} finally {
if (null != jedis) {
jedis.close();
}
}
return var9;
}
protected String checkAndReturnKey(String namespace, String key) {
if (!StringUtils.isBlank(namespace) && !StringUtils.isBlank(key)) {
return namespace + "_" + key;
} else {
log.debug("redis for namespace or key is null,namespace: {} key:{}", namespace, key);
}
return namespace;
}
private byte[] getBytes(String key) {
Jedis jedis = jedisPool.getResource();
Object var4 = null;
try {
byte[] bytes = jedis.get(key.getBytes("UTF-8"));
if (bytes != null) {
byte[] var10 = bytes;
return var10;
}
var4 = null;
} catch (UnsupportedEncodingException | JedisConnectionException var8) {
log.error("redis for key: {}", key, var8);
} finally {
if (null != jedis) {
jedis.close();
}
}
return (byte[])var4;
}
public Set<String> keysByScan(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
Set<String> keys = new HashSet();
long start = System.currentTimeMillis();
try {
String cursor = ScanParams.SCAN_POINTER_START;
ScanParams scanParams = new ScanParams();
scanParams.match(key + "*");
scanParams.count(1000);
while(true) {
ScanResult<String> scanResult = jedis.scan(cursor, scanParams);
cursor = scanResult.getCursor();
List<String> list = scanResult.getResult();
if (!CollectionUtils.isEmpty(list)) {
keys.addAll(list);
}
if (keys.size() >= 100) {
log.info("总共获取 {}条数据,耗时: {}毫秒", keys.size(), System.currentTimeMillis() - start);
} else {
if (!"0".equals(cursor)) {
continue;
}
log.info("总共获取 {}条数据,耗时: {}毫秒", keys.size(), System.currentTimeMillis() - start);
}
HashSet var16 = (HashSet) keys;
return var16;
}
} catch (JedisConnectionException var14) {
log.error("redis for key: {}", key, var14);
} finally {
if (null != jedis) {
jedis.close();
}
}
return keys;
}
public long incrAuto(String namespace, String key, int seconds) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
long result = 0L;
try {
result = jedis.incr(key);
if (result == 1L) {
jedis.expire(key, seconds);
}
} catch (Exception var11) {
log.error("incrAuto for key: {}", key, var11);
} finally {
if (null != jedis) {
jedis.close();
}
}
return result;
}
public boolean sismember(String namespace, String key, String member) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
try {
boolean result = jedis.sismember(key, member);
boolean var6 = result;
return var6;
} catch (Exception var10) {
log.error("Error sismember cache for key: {}", key, var10);
} finally {
if (null != jedis) {
jedis.close();
}
}
return false;
}
public Set<String> smembers(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
Set<String> members = null;
Jedis jedis = jedisPool.getResource();
try {
members = jedis.smembers(key);
Set var5 = members;
return var5;
} catch (Exception var9) {
log.error("Error smembers cache for key: {}", key, var9);
} finally {
if (null != jedis) {
jedis.close();
}
}
return members;
}
public long sadd(String namespace, String key, String... members) {
key = this.checkAndReturnKey(namespace, key);
long bReturn = 0L;
Jedis jedis = jedisPool.getResource();
try {
bReturn = jedis.sadd(key, members);
} catch (Exception var11) {
log.error("Error sadd key {}:", key, var11);
} finally {
if (null != jedis) {
jedis.close();
}
}
return bReturn;
}
public long expire(String namespace, String key, int seconds) {
key = this.checkAndReturnKey(namespace, key);
long bReturn = 0L;
Jedis jedis = jedisPool.getResource();
try {
bReturn = jedis.expire(key, seconds);
} catch (Exception var11) {
log.error("Error expire key {}:", key, var11);
} finally {
if (null != jedis) {
jedis.close();
}
}
return bReturn;
}
public Set<String> keys(String namespace) {
if (StringUtils.isBlank(namespace)) {
log.error("redis for namespace or key is null,namespace: {} ", namespace);
} else {
Jedis jedis = jedisPool.getResource();
Set<String> result = null;
try {
result = jedis.keys(namespace + "*");
Set var4 = result;
return var4;
} catch (Exception var8) {
log.error("Error expire namespace {}:", namespace, var8);
} finally {
if (null != jedis) {
jedis.close();
}
}
return result;
}
return null;
}
public Long getTTl(String namespace, String key) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
long ttl = 0L;
try {
ttl = jedis.ttl(key);
} catch (Exception var10) {
log.error("Error expire namespace {}:", namespace, var10);
} finally {
if (null != jedis) {
jedis.close();
}
}
return ttl;
}
public boolean setnx(String namespace, String key, String value, long seconds) {
key = this.checkAndReturnKey(namespace, key);
Jedis jedis = jedisPool.getResource();
try {
SetParams setParams = new SetParams();
setParams.ex(seconds);
setParams.nx();
String res = jedis.set(key, value, setParams);
boolean var9;
if ("OK".equals(res)) {
var9 = true;
return var9;
}
var9 = false;
return var9;
} catch (Exception var13) {
log.error("Error setnx cache for key: {}", key, var13);
} finally {
if (null != jedis) {
jedis.close();
}
}
return false;
}
}
CachePoolProvider.java
package com.example.user.utils.redis;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;
@Configuration
@ConfigurationProperties(prefix = "redis")
@Component
@Slf4j
@Data
//当一个类实现InitializingBean这个接口之后,Spring启动后,初始化Bean时,
// 若该Bean实现InitialzingBean接口,会自动调用afterPropertiesSet()方法,完成一些用户自定义的初始化操作
//因为static比InitializingBean先执行,实例JedisPool是static的,必须在static后调用afterPropertiesSet(),这样@Configuration才能赋值成功
public class CachePoolProvider implements InitializingBean {
private String host;
private int port;
private String password;
private int db;
private JedisPool CACHE_POOL = null;
public CachePoolProvider() {
}
public void afterPropertiesSet() throws Exception {
RedisConstants.REDIS_HOST = this.host;
RedisConstants.REDIS_PORT = this.port;
RedisConstants.REDIS_PASS = this.password;
RedisConstants.REDIS_DB = this.db;
if (!"null".equals(this.host) && this.port != -1 && !"null".equals(this.password) && this.db != -1) {
this.CACHE_POOL = this.GetPool();
//初始化jedisPool
CacheManager.jedisPool = this.CACHE_POOL;
}
}
public JedisPool GetPool() {
if (this.CACHE_POOL == null) {
Class var1 = CachePoolProvider.class;
synchronized(CachePoolProvider.class) {
if (this.CACHE_POOL == null) {
Set<String> sentinels = new HashSet();
if (sentinels.size() > 0) {
log.info("Connecting to redis with sentinels :{}", sentinels);
} else {
String host = RedisConstants.REDIS_HOST;
int port = RedisConstants.REDIS_PORT;
String pass = RedisConstants.REDIS_PASS;
int maxIdle = 10;
int maxTotal = 10;
int dbIndex = RedisConstants.REDIS_DB;
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxTotal(maxTotal);
pass = StringUtils.isBlank(pass) ? null : pass;
log.info("Connecting to redis {}:{} maxtotal:{}", new Object[]{host, port, Integer.valueOf(maxTotal)});
this.CACHE_POOL = new JedisPool(new JedisPoolConfig(), host, port, 10000, pass, dbIndex);
}
}
}
}
return this.CACHE_POOL;
}
public void shutdown() {
if (this.CACHE_POOL != null) {
this.CACHE_POOL.destroy();
this.CACHE_POOL = null;
}
}
}
JedisService.java
package com.example.user.utils.redis;
public interface JedisService {
/**
*保存数据
*/
boolean set(final String namespace, String key, String value, long expire);
/**
*获取数据
*/
String get(final String namespace, String key);
/**
*删除数据
*/
boolean del(final String namespace, String key);
/**
*保存数据
*/
boolean setNx(String namespace, String key, String value, long expire);
/**
* 自增
*/
long incr(String namespace, String key, int expire);
}
JedisServiceImpl.java
package com.example.user.utils.redis;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@Service
public class JedisServiceImpl implements JedisService{
private CacheManager cacheManager = new CacheManager<>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public String getDataByReadWriteLock(String namespace,String key) {
//获取读锁
lock.readLock().lock();
try{
//如果缓存有效, 直接使用data
String data = (String) cacheManager.get(namespace,key);
if(!StringUtils.isEmpty(data)){
return data;
}
}finally {
//释放读锁
lock.readLock().unlock();
}
//获取写锁
lock.writeLock().lock();
try{
//如果缓存无效,更新cache;有效时间120秒
cacheManager.save(namespace,key,"从数据库查的数据",120);
return "从数据库查的数据";
}finally {
//释放写锁
lock.writeLock().unlock();
}
}
public boolean set(String namespace, String key, String value, long expire) {
return cacheManager.save(namespace, key, value, expire);
}
public String get(String namespace, String key) {
if (StringUtils.isEmpty(key)) {
return null;
}
return (String) cacheManager.get(namespace, key);
}
public boolean del(String namespace, String key) {
return cacheManager.remove(namespace, key);
}
public synchronized boolean setNx(String namespace, String key, String value, long expire) {
return cacheManager.setnx(namespace, key, value, expire);
}
public long incr(String namespace, String key, int expire) {
return cacheManager.incrAuto(namespace, key, expire);
}
}
RedisConstants.java
package com.example.user.utils.redis;
public class RedisConstants {
public static String REDIS_HOST;
public static int REDIS_PORT;
public static String REDIS_PASS;
public static int REDIS_DB;
public RedisConstants() {
}
}
5.用于测试的controller,最后启动SpringBoot测试即可
package com.example.user.controller;
import com.example.user.dal.UserRepository;
import com.example.user.domain.User;
import com.example.user.utils.redis.JedisServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Controller
public class UserController {
@Autowired
private JedisServiceImpl redisService;
@GetMapping("/redisTest")
@ResponseBody
public String redisTest() {
//实际redis储存的key为 你的命名空间_123456
redisService.set("你的命名空间","123456","mockData",120);
System.out.println(redisService.get("你的命名空间","123456"));
return "";
}
}