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