摘要:在查詢的服務方法上添加如下注解表明該方法的返回值需要緩存。當被緩存的數據發生改變,緩存需要被清理或者修改,這里使用如下注解清除指定的緩存。事務是一個原子操作,所有的緩存,消息,這種非強一致性要求的操作,都應該在事務成功提交后執行。
【為什么使用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啟動類上表明啟用緩存:@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【自定義序列化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【自定義key生成策略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 + "::"; } }【使用spring注解操作緩存
在使用的類(讀與寫的類都需要)上我們使用如下注解表明這個服務使用緩存的名稱是什么,也可以直接在方法上指明cacheName但是要寫多次。
@CacheConfig(cacheNames = RedisCacheName.KILL_PRODUCT)
在查詢的服務方法上添加如下注解表明該方法的返回值需要緩存。
@Cacheable(keyGenerator = "keyGenerator")
當被緩存的數據發生改變,緩存需要被清理或者修改,這里使用如下注解清除指定key的緩存。
@CacheEvict(keyGenerator = "keyGenerator")
使用redis-cli命令進入redis(docker exec -it containerId redis-cli) 輸入keys * 查看所有的緩存 我們可以看見緩存是按照cacheName + "::" + id 的方式生成的,而我們的key生成策略也是針對于生成id的那一部分。【值得注意的一點
我們在使用緩存的時候應該注意緩存的對象應該處于哪一層,試想如果我的緩存在dao這一層,但是事務在service層,一個service方法包含了多個dao方法,如果在執行service方法的時候,擁有緩存的dao方法成功,但是接下來的到方法失敗,那么我們的緩存就生效了,但是數據并沒有落庫,這就產生了數據不一致的問題。所以我們的緩存應該在事務的更上層。事務是一個原子操作,所有的緩存,消息,這種非強一致性要求的操作,都應該在事務成功提交后執行。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/69084.html
摘要:但是經過測試自身的是次秒,是一個相當不錯的數據,所以我們這里將事務直接交給,使用存儲過程來降低行級鎖的持有時間。存儲過程代碼使用存儲過程之前必須保證數據庫已經創建了存儲過程。表示使用在存儲過程中替代最后需要還原回來。 【什么是存儲過程 所謂的存儲過程是指:是一組為了完成特定功能的SQL語句集,經編譯后存儲在數據庫中,用戶通過指定存儲過程的名字并給定參數(如果該存儲過程帶有參數)來調用執...
摘要:當秒殺日期尚未達到會提示用戶秒殺尚未開始當用戶多次秒殺同一商品會提示用戶重復秒殺當秒殺日期過期或者秒殺商品的庫存為零會提示用戶秒殺結束。 【秒殺系統業務分析 在秒殺系統當中有兩個核心的表:秒殺商品(kill_product)與秒殺明細(kill_item),具體的邏輯是一個用戶秒殺商品的庫存減一,秒殺明細的記錄增加一條。這兩步作是處于同一事務之中。 當秒殺日期尚未達到會提示用戶秒殺尚...
閱讀 2266·2021-11-25 09:43
閱讀 3137·2021-10-14 09:42
閱讀 3492·2021-10-12 10:12
閱讀 1578·2021-09-07 10:17
閱讀 1909·2019-08-30 15:54
閱讀 3193·2019-08-30 15:54
閱讀 1568·2019-08-30 15:53
閱讀 1926·2019-08-29 11:21