1.首先在build.gradle中引入redis的依赖: compile('org.springframework.boot:spring-boot-starter-data-redis') 其实作完这一步咱们已经能够直接使用springboot提供的RedisTemplate,可是咱们须要进一步优化,而且使用注解配置缓存 2.添加缓存配置类: - KeyGenerator代表咱们本身定义key生成的策略 - RedisCustomSerializer代表咱们本身定义序列化的方式,这里使用了protostuff来序列化,protostuff是目前最高效,节省空间的序列化方式 3.在springboot启动类上代表启用缓存:@EnableCaching 4.定义缓存的名称集合,统一管理缓存名称 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 */ @Configuration public class RedisConfig extends CachingConfigurerSupport { @Override @Nullable @Bean public KeyGenerator keyGenerator() { return new RedisCustomKeyGenerator(); } @Bean public RedisTemplate<String, String> 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<KillProduct> 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的标示,是的程序中必须将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 + "::"; } }
使用redis-cli命令进入redis(docker exec -it containerId redis-cli) 输入keys * 查看全部的缓存 咱们能够看见缓存是按照cacheName + "::" + id 的方式生成的,而咱们的key生成策略也是针对于生成id的那一部分。
咱们在使用缓存的时候应该注意缓存的对象应该处于哪一层,试想若是个人缓存在dao这一层,可是事务在service层,一个service方法包含了多个dao方法,若是在执行service方法的时候,拥有缓存的dao方法成功,可是接下来的到方法失败,那么咱们的缓存就生效了,可是数据并无落库,这就产生了数据不一致的问题。因此咱们的缓存应该在事务的更上层。事务是一个原子操做,全部的缓存,消息,这种非强一致性要求的操做,都应该在事务成功提交后执行。java