java 缓存解决方案之单体服务实战
作者:互联网
java在单体服务中 缓存解决方案,它是高并发首选策略
一、什么样的数据适合缓存?
1、访问频率高
2、更改频率低
3、一致性要求不高
在 Java 中,使用场景 我们一般对调用方法进行缓存控制,比如我调用"findUserById(int id)", 那么我应该在调用这个方法之前先从缓存中查找有没有,如果没有再调用该方法如从数据 库加载用户信息,然后添加到缓存中,再加上相应的失效时间,下次调用时将会从缓存中获取到数据;如果需要对用户信息进行更新,可以采用双删原则更新数据库,此方案也能解决过呢更新的陷阱(如下图所示:);如果删除此用户,也可采用双删原则。Java 中广泛使 用的缓存工具 Redis 二、缓存效能 --最小内存(昂贵) --- 最大功用1、重要的指标:
命中率 = 从缓存中读取次数 / (总读取次数[从缓存中读取次数 + 从慢速设备上读取的次数])
Miss率 = 没有从缓存中读取的次数 / (总读取次数[从缓存中读取次数 + 从慢速设备上读取的次数])
二、项目实战: 1、缓存逻辑流程图如下:2、实战项目yml配置:
server:
port: 88890
compression:
enabled: true
connection-timeout: 3000
spring:
redis:
host: 192.168.0.128
port: 6380
datasource:
url: jdbc:mysql://192.168.0.128:3306/nandao?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
username: root
password: root
driverClassName : com.mysql.jdbc.Driver
test-on-borrow: false
test-while-idle: true
time-between-eviction-runs-millis: 3600000
mybatis:
mapperLocations: classpath:mapper/*.xml
3、redis初始化配置:json 序列化有两种方式,根据实际业务场景具体选择。
@Configuration
public class CacheConfig extends CachingConfigurerSupport {
/**
* 序列化object对象为json字符串
*/
/* @Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}*/
/**
* JdkSerializationRedisSerializer: 序列化java对象(被序列化的对象必须实现Serializable接口),无法转义成对象
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//使用jdk的序列化
template.setValueSerializer(new JdkSerializationRedisSerializer());
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
3、核心逻辑流程代码:
/**
* 编码实现redis缓存
*/
@Service("TestprovincesService")
public class ProvincesServiceImpl1 extends ProvincesServiceImpl implements ProvincesService{
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//业务查询的接口
@Override
public Provinces detail(String provinceid) {
Provinces provinces = null;
//首先在redis查询
provinces = (Provinces)redisTemplate.opsForValue().get(provinceid);
if (null != provinces){//查询到结果
redisTemplate.expire(provinceid,20000, TimeUnit.MILLISECONDS);
System.out.println("缓存中得到数据");
return provinces;
}
//如果缓存中没有查到,则需要到数据库中查询
provinces = super.detail(provinceid);
if (null != provinces){
//从数据库查到数据后放到缓存中,并加上失效时间
redisTemplate.opsForValue().set(provinceid,provinces);//set缓存
redisTemplate.expire(provinceid,20000, TimeUnit.MILLISECONDS);//设置过期
}
return provinces;
}
//更新的业务接口,并清除缓存;当然也可以不删除而直接更新缓存
@Override
public Provinces update(Provinces entity) {//双删
redisTemplate.delete(entity.getProvinceid());//直接删除缓存,预防数据库成功,缓存失败
super.update(entity);
redisTemplate.delete(entity.getProvinceid());//双删
return entity;
}
@Override
public Provinces add(Provinces entity) {
redisTemplate.delete(entity.getProvinceid());//set a=2
super.add(entity);
redisTemplate.delete(entity.getProvinceid());//双删
return entity;
}
@Override
public void delete(String provinceid) {
redisTemplate.delete(provinceid);
super.delete(provinceid);
redisTemplate.delete(provinceid);//双删
}
}
此缓存方案是常规的解决方案,下篇我们分享
基于Spring注解的 Cache 解决方案 ,敬请期待!
标签:缓存,java,解决方案,entity,template,序列化,provinceid,redisTemplate 来源: https://blog.csdn.net/nandao158/article/details/112744451