博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java并发编程学习20--基于springboot的秒杀系统实现2--redis缓存
阅读量:7048 次
发布时间:2019-06-28

本文共 5198 字,大约阅读时间需要 17 分钟。

【为什么使用redis

  • 性能极高,redis能读的速度是110000次/s,写的速度是81000次/s
  • 丰富的数据类型,redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作
  • redis命令友好易用
  • springboot 已经自动集成了redis

【redis配置

1.首先在build.gradle中引入redis的依赖:compile('org.springframework.boot:spring-boot-starter-data-redis')其实做完这一步我们已经可以直接使用springboot提供的RedisTemplate,但是我们需要进一步优化,并且使用注解配置缓存2.添加缓存配置类: - KeyGenerator表明我们自己定义key生成的策略 - RedisCustomSerializer表明我们自己定义序列化的方式,这里使用了protostuff来序列化,protostuff是目前最高效,节省空间的序列化方式     3.在springboot启动类上表明启用缓存:@EnableCaching4.定义缓存的名称集合,统一管理缓存名称5.在需要使用缓存的查询服务上使用:@Cacheable(keyGenerator = "keyGenerator")6.在需要清理缓存的业务服务上使用:@CacheEvict(keyGenerator = "keyGenerator")

图片描述

【缓存配置类

import org.springframework.cache.annotation.CachingConfigurerSupport;import org.springframework.cache.interceptor.KeyGenerator;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.cache.RedisCacheConfiguration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.RedisSerializationContext;import org.springframework.lang.Nullable;import java.time.Duration;/** * redis缓存配置类 * @author ibm * @since 0 * @date 2018-4-12 */@Configurationpublic class RedisConfig extends CachingConfigurerSupport {    @Override    @Nullable    @Bean    public KeyGenerator keyGenerator() {        return new RedisCustomKeyGenerator();    }    @Bean    public RedisTemplate
redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); RedisCustomSerializer customSerializer = new RedisCustomSerializer(); template.setValueSerializer(customSerializer); template.afterPropertiesSet(); return template; } /** * 设置 redis 数据默认过期时间 * 设置@cacheable 序列化方式 * @return */ @Bean public RedisCacheConfiguration redisCacheConfiguration(){ RedisCustomSerializer customSerializer = new RedisCustomSerializer(); RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer (customSerializer)).entryTtl(Duration.ofHours(1)); return configuration; }}

【自定义序列化

import com.example.seckill.dao.entity.KillProduct;import io.protostuff.LinkedBuffer;import io.protostuff.ProtostuffIOUtil;import io.protostuff.runtime.RuntimeSchema;import org.springframework.data.redis.serializer.RedisSerializer;import org.springframework.data.redis.serializer.SerializationException;import org.springframework.lang.Nullable;/** * 自定义的redis序列化 * @author ibm * @since 0 * @date 2018-4-22 */public class RedisCustomSerializer implements RedisSerializer {    private final RuntimeSchema
schema = RuntimeSchema.createFrom(KillProduct.class); @Nullable @Override public byte[] serialize(@Nullable Object o) throws SerializationException { KillProduct killProduct = (KillProduct)o; byte[] bytes = ProtostuffIOUtil.toByteArray(killProduct,schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE)); return bytes; } @Nullable @Override public Object deserialize(@Nullable byte[] bytes) throws SerializationException { if(bytes != null){ KillProduct killProduct = schema.newMessage(); //反序列化 ProtostuffIOUtil.mergeFrom(bytes,killProduct,schema); return killProduct; }else { return null; } }}

【自定义key生成策略

这里有一个不好的地方是我直接使用第一个参数作为key的标示,是的程序中必须将id放在第一位,但这里只是一个事例,表明我们的key可以在这里进行自定义。
import org.springframework.cache.interceptor.KeyGenerator;import java.lang.reflect.Method;/** * 自定义的redis缓存key生成策略 * @author ibm * @since 0 * @date 201804013 */public class RedisCustomKeyGenerator implements KeyGenerator {    /**     * 简单的指定生成killProduct的缓存id,这里可以根据业务类型自定义所有的key生成策略     * @param target   被调用方法的类实例     * @param method  方法的名称     * @param params 方法的参数     * @return 缓存key     */    @Override    public Object generate(Object target, Method method, Object... params) {        return params[0];    }    /**     * 提供redisTemplate使用的key查询方法     * @param cacheName 缓存名称     * @return 缓存的key前缀     */    public static final String getKey4CacheName(String cacheName){        //spring在生成key的时候会用cacheName::的前缀        return cacheName + "::";    }}

【使用spring注解操作缓存

  • 在使用的类(读与写的类都需要)上我们使用如下注解表明这个服务使用缓存的名称是什么,也可以直接在方法上指明cacheName但是要写多次。
    @CacheConfig(cacheNames = RedisCacheName.KILL_PRODUCT)
  • 在查询的服务方法上添加如下注解表明该方法的返回值需要缓存。
    @Cacheable(keyGenerator = "keyGenerator")
  • 当被缓存的数据发生改变,缓存需要被清理或者修改,这里使用如下注解清除指定key的缓存。
    @CacheEvict(keyGenerator = "keyGenerator")

图片描述

图片描述

【redis客户端查看缓存

使用redis-cli命令进入redis输入keys * 查看所有的缓存我们可以看见缓存是按照cacheName + "::" + id 的方式生成的,而我们的key生成策略也是针对于生成id的那一部分。

图片描述

【值得注意的一点

我们在使用缓存的时候应该注意缓存的对象应该处于哪一层,试想如果我的缓存在dao这一层,但是事务在service层,一个service方法包含了多个dao方法,如果在执行service方法的时候,拥有缓存的dao方法成功,但是接下来的到方法失败,那么我们的缓存就生效了,但是数据并没有落库,这就产生了数据不一致的问题。所以我们的缓存应该在事务的更上层。事务是一个原子操作,所有的缓存,消息,这种非强一致性要求的操作,都应该在事务成功提交后执行。

转载地址:http://sjkol.baihongyu.com/

你可能感兴趣的文章
SpringMVC源码分析3:DispatcherServlet的初始化与请求转发
查看>>
Hyper-V故障转移群集搭建(3)
查看>>
VMware下ubuntu上网设置(二)
查看>>
sqlplus的session下无法使用退格键的问题处理
查看>>
Centos7下部署本地的gitlab(CE版本)
查看>>
docker配置桥接网络
查看>>
PHP使用file_get_contents函数POST数据
查看>>
mariadb安装
查看>>
MySQL基础day07_mysql集群实例-MySQL 5.6
查看>>
高性能 Web 缓存服务器 nuster 1.7.9.5 发布
查看>>
nginx对后端的目录进行反向代理
查看>>
NAT(Cisco)
查看>>
HP LaserJet Pro P1106网络打印机64位驱动安装
查看>>
SpringMVC+MyBatis整合(1)generator篇
查看>>
XMPP getting "Not Authorized" when joining an P/W protected, already open chat room
查看>>
C#设计模式之总结篇
查看>>
基于Sbo 2005B的富盛企业经营分析插件共享版免费下载
查看>>
手机上的搜索引擎-Windows Live Search Mobile 发布!
查看>>
五元组和防火墙
查看>>
Mac下添加java环境变量
查看>>