- 一种nosql 单线程的数据库做缓存的简单使用
- 对curd的操作,为了保证数据的一致性,除了查询,其它操作都要进行数据更新和删除
- redis的协议:Redis服务器与客户端通过RESP(REdis Serialization Protocol)协议通信,了解了Redis协议的基本数据类型,就可以通过Socket与Redis Server进行通信,客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾。
- 缓存击穿 指查询一个一定不存在的数据要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞;解决方法如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短
- 缓存雪崩 缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩;解决方案在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,降低几率;或则加锁,队列
- 关于缓存击穿和雪崩参考
安装服务
- http://www.redis.cn/ 下载最新redis4.01
-
#tar -zxvf redis... --解压
-
#mv file filepath --移动到你想安装的目录
-
#cd /redis
-
#make MALLOC=libc --管理内存碎片
-
#make && make install --编译并安装
-
#cd src && redies-server 如图
配置
-
#vi /home/redis/src/redis.conf --编写配置文件,写入已下配置,指定端口-父进程pid-守护进程
-
#通过src/redis-server redis.conf 启动 通过#redis-cli shutdown 来停止服务
- 会有两个端口打开未发现有什么错误,可以禁用ip6,
-
#firewall-cmd --zone=public --add-port=6379/tcp --perment
-
#vi /usr/lib/systemd/system/redis.service --编写服务单元交与systemd 管理
rdb和aof 两种持久化方案详情1详情2
- rdb 是基于快照的,通过save seconds frequency,进行周期性的备份默认开启,当服务器出现故障可能会丢失最后一次的数据。数据恢复速度快适合数据的备份。
-
aof 是基于日志记录的,保持了高一致性。数据比较全面文件比较大恢复稍慢。默认是关闭的通过appendonly yes开启。
简单的使用
- 使用java操作jedis客户端
- 编写jedisManager
导入依赖
redis.clients
jedis
2.9.0
redis的连接初始化类
public class JedisManager {
private static String host = "192.168.1.200";
private static int port = 6379;
private JedisPoolConfig jpc;
private static JedisPool jedisPool;
private static int timeOut;
/**
* 初始化连接池
**/
static {
if (timeOut == 0){
timeOut = Protocol.DEFAULT_TIMEOUT;
}
jedisPool = new JedisPool(host,port);
}
/**
* 从连接池中获取连接
**/
public static Jedis getJedis(){
if (jedisPool != null){
return jedisPool.getResource();
}else throw new NullPointerException("jedisPool is null");
}
/**
* 把连接返回给jedispool
**/
public static void returnResource(Jedis jedis) {
if (jedis != null){
jedisPool.close();
}
}
/**
* 关闭连接池
**/
public void shutDown(){
if (jedisPool != null){
jedisPool.destroy();
}
}
}
String类型的测试
public class JedisDao {
//存储字符串
public void cacheString(){
Jedis jedis = JedisManager.getJedis();
System.out.println(jedis);
jedis.set("name","hahaha");
System.out.println(jedis.get("name"));
//拼接
jedis.append("name","is 爸爸");
System.out.println(jedis.get("name"));
JedisManager.returnResource(jedis);
}
}
测试结果
redis.clients.jedis.Jedis@7bb11784
hahaha
hahahais 爸爸
Process finished with exit code 0
- 整合spring 分别在service层缓存,利用spirng aop 对目标方法进行缓存
导入依赖
redis.clients
jedis
2.9.0
org.springframework.data
spring-data-redis
1.7.2.RELEASE
aspectj
aspectjweaver
1.5.4
redis.properties
redis.host=192.168.1.200
redis.port=6379
redis.password=
#最大空闲数
redis.maxIdel=300
#连接池连接数
redis.maxActive=600
#最大等待时间
redis.maxWait=1000
#实例均用
redis.testOnBorrow=true
reids-cfg.xml
classpath:redis.properties
放入spring的主配置文件
- 测试在service层进行缓存
需要的工具类
@Component
public class RedisCacheUtil {
@Autowired
private RedisTemplate redisTemplate;
/**
* 删除对应的value
**/
public void remove(final String... args){
for (String key:args){
remove(key);
}
}
public boolean remove(String key){
boolean flag = false;
try {
if (exists(key)){
redisTemplate.delete(key);
flag = true;
}
}catch (Exception e) {
System.out.println(e.toString());
}
return flag;
}
public boolean exists(String key) {
return redisTemplate.hasKey(key);
}
/**
* 删除keys
**/
public void removePattern(final String pattern){
Set keys = redisTemplate.keys(pattern);
if (keys.size()>0){
redisTemplate.delete(keys);
}
}
/**
* 根据key读取缓存
**/
public Object get(final String key){
return redisTemplate.opsForValue().get(key);
}
/**
* 写入缓存
**/
public boolean set(final String key, Object value){
try {
redisTemplate.opsForValue().set(key,value);
return true;
}catch (Exception e){
System.out.println(e.toString());
return false;
}
}
public boolean set(final String key, Object value, Long time){ //设置过期时间
try {
redisTemplate.opsForValue().set(key, value);
redisTemplate.expire(key,time, TimeUnit.SECONDS);
return true;
}catch (Exception e){
return false;
}
}
}
缓存的容器
/**
* Created by: jun on 2018/1/7.
* description: 创建redis的储存器接口
*/
public interface RedisCacheStorage {
//key,value 普通类型
boolean set(k key, v value); //永久缓存
boolean set(k key, v value, Long time); //time内缓存
boolean remove(k key); //删除
v get(k key); //获取
}
// 实现的接口
@Component
public class RedisCacheStorageImpl implements RedisCacheStorage {
@Autowired
private RedisCacheUtil redisCacheUtil;
@Override
public boolean set(String key, v value) {
return redisCacheUtil.set(key,value);
}
@Override
public boolean set(String key, v value, Long time) {
return redisCacheUtil.set(key,value,time);
}
@Override
public boolean remove(String key) {
return redisCacheUtil.remove(key);
}
@Override
public v get(String key) {
return (v) redisCacheUtil.get(key);
}
}
实体类,一定要序列化,spirng 才能进行装配
public class User implements Serializable {
private Integer id;
private String name;
private String pwd;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
开始缓存
@Service
public class UserServiceImpl implements UserService {
private static final String cacheKey = "userEntity"; //缓存的key
private static final Long time = 10000l;
@Autowired
private UserMapper userMapper;
@Autowired
private RedisCacheStorage cacheStorage;
@Override
public List select() {
//先查找缓存
List userList;
userList = (List) cacheStorage.get(cacheKey);
if (userList != null) {
System.out.println("读取了缓存");
return userList;
} else {
//开始查找数据库,放入缓存
userList = userMapper.selectAll();
cacheStorage.set(cacheKey, userList);
System.out.println("已添加缓存");
return userList;
}
}
测试结果
- 测试基于aop配置文件目标方法的缓存
实现MethodInterceptor接口的切面,在redis.properties中写入需要缓存的方法如果与aop拦截的方法对应则进行缓存
/**
* Created by: jun on 2018/1/3.
* description: 实现spring MethodInterceptor接口,使用aop对方法级的进行缓存。
* 根据配置文件给不同的方法加入判断是否缓存数据,第一次从缓存中读取,并将结果进行缓存
*/
public class MethodCacheInterceptor implements MethodInterceptor {
@Autowired
private RedisCacheUtil redisCacheUtil;
private List cacheClassList; //缓存的serice类
private List cacheMethodList; //缓存的方法
private Long timeOut = 1000l; //过期时间
private String resourcesName = "redis.properties"; //缓存的配置文件
private String fileClassValue = "cacheClass"; //配置文件设置缓存的类字段
private String fileMethodValue = "cacheMethod"; //配置文件中缓存的方法字段
/**
* 初始化读取需要缓存的类和方法
* 在reids.properties中添加缓存的方法和类
*
**/
public MethodCacheInterceptor() throws IOException {
// 在 resources 下读取配置文件
InputStream in = ConfProLoader.getClassPathFile(resourcesName);
Properties p = new Properties();
p.load(in);
//分割,获取每个类和方法
String[] cacheClass = p.getProperty(fileClassValue).split(",");
String[] cacheMethod = p.getProperty(fileMethodValue).split(",");
//将方法和类存入list
cacheClassList = new ArrayList(cacheClass.length);
cacheMethodList = new ArrayList(cacheMethod.length);
int maxLength = cacheClass.length > cacheMethod.length ? cacheClass.length
: cacheMethod.length;
for (int i=0; i0) sb.append("_").append(arguments[i]);
}
return sb.toString();
}
}
在reids的资源文件中写入需要缓存的类和方法。如果拦截的方法和配置文件中对应,则对该方法进行缓存
host=192.168.1.200
port=6379
password=
#连接池连接数
maxTotal=400
#最大空闲数
maxIdel=300
#最大等待时间
maxWait=1000
#实例均用
testOnBorrow=true
#需要缓存的类
cacheClass=comm.tianzhuan.web.service.impl.UserServiceImpl,test1
#要缓存的方法
cacheMethod=selectt,hahaha
#设置缓存失效时间
test=60
test1=60
defaultCacheExpireTime=3600
spirng中配置aop
测试的结果
@Test
public void test(){
List userList = userService.select();
System.out.println(userList);
}