Redis缓存技术学习一
缓存需要注意的几点
- 缓存穿透:当我们查询数据时候,数据库中没有我们查询的数据,而且缓存中也没有
解决:在缓存中存储当前数据主键的最大值 (自增),把所有主键的值放入缓存中 - 缓存雪崩:缓存中大量的数据在极短的时间到期
解决:让数据一部分一部分的到期
缓存穿刺:大量的请求访问数据库, 解决:加锁
- 导入依赖包
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>`
2.添加配置文件
redis:
host: 10.9.251.200
port: 8100
password: //密码
jedis:
pool:
min-idle: 10
max-idle: 100
max-active: 1024
3.创建对象
/**
* Redis配置类
*/
@Configuration
public class RedisConfig {
//使用注解加载配置文件的内容
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Bean
public JedisPool jedisPool(JedisPoolConfig jedisPoolConfig) {
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, 5000, password);
return jedisPool;
}
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//设置config的属性
jedisPoolConfig.setMaxTotal(1024);
jedisPoolConfig.setMaxIdle(100);
jedisPoolConfig.setMinIdle(10);
return jedisPoolConfig;
}
}
4.编写缓存工具类,将数据存放入缓存中
public class RedisUtils {
public static void hset(String key, Notice notice, Jedis jedis) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
Class aClass = notice.getClass();
//获得实体类中的各个属性
Field[] declaredFields = aClass.getDeclaredFields();
//进行遍历
for (Field declaredField : declaredFields) {
//获得属性的名称
String name = declaredField.getName();
//PropertyDescriptor作用就是获得属性的get和set方法,参数为属性名和类的对象
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(name, aClass);
//不为空说明方法存在
if (propertyDescriptor != null) {
//getReadMethod 获取属性的get方法
Method readMethod = propertyDescriptor.getReadMethod();
//得到结果
Object result = readMethod.invoke(notice);
if (result != null) {
//调用jedis的方法,加入缓存
jedis.hset(key, name, result.toString());
}
}
}
}
}
4.使用缓存,首先查看缓存中是否有我们需要的数据 如果没有查询数据库
/**
* 查询详情
* @param notice_id
* @param user_id
* @return
*/
@Override
public ResultBean getDetail(int notice_id, int user_id) {
Jedis jedis = null;
try {
//从缓存池中获取 缓存对象
jedis = jedisPool.getResource();
//先从缓存中查询 规定key为 notice_id:id user_id:id
String key = "notice" + notice_id + "user" + user_id;
//查看缓存中是否是需要的数据
Map<String, String> map = jedis.hgetAll(key);
if (map == null || map.isEmpty()) {
//放穿透---查询数据库中时候有该数据的id值
Boolean fangchuntou = jedis.sismember("fangchuantou_jll", String.valueOf(notice_id));
//如果数据库有该数据,查询数据库
if (fangchuntou) {
//从数据库中查询
Notice notice = noticeMapper.findNoticeByNotice_idAndUser_id(notice_id, user_id);
if (notice != null) {
//调用工具类,放入缓存
RedisUtils.hset(key, notice, jedis);
//设置有效期
jedis.expire(key, 1800);
return ResultBean.setOK(notice);
}
}
}else {
ResultBean.setOK(map);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
return ResultBean.setERROR("没有此商品");
}
}
5.防穿透的设置,服务器开启之前将数据库中数据的id存入缓存中
@PostConstruct
public void init() {
Jedis jedis = jedisPool.getResource();
//查询数据库id
List<Integer> ids = noticeMapper.findNoticeAllId();
jedis.sadd("fangchuantou_jll", ids.toArray().toString());
jedis.close();
}