国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

java并發(fā)編程學(xué)習(xí)20--基于springboot的秒殺系統(tǒng)實現(xiàn)2--redis緩存

bovenson / 2306人閱讀

摘要:在查詢的服務(wù)方法上添加如下注解表明該方法的返回值需要緩存。當(dāng)被緩存的數(shù)據(jù)發(fā)生改變,緩存需要被清理或者修改,這里使用如下注解清除指定的緩存。事務(wù)是一個原子操作,所有的緩存,消息,這種非強(qiáng)一致性要求的操作,都應(yīng)該在事務(wù)成功提交后執(zhí)行。

【為什么使用redis

性能極高,redis能讀的速度是110000次/s,寫的速度是81000次/s

豐富的數(shù)據(jù)類型,redis支持二進(jìn)制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作

redis命令友好易用

springboot 已經(jīng)自動集成了redis

【redis配置
1.首先在build.gradle中引入redis的依賴:
compile("org.springframework.boot:spring-boot-starter-data-redis")
其實做完這一步我們已經(jīng)可以直接使用springboot提供的RedisTemplate,但是我們需要進(jìn)一步優(yōu)化,并且使用注解配置緩存

2.添加緩存配置類:
 - KeyGenerator表明我們自己定義key生成的策略
 - RedisCustomSerializer表明我們自己定義序列化的方式,這里使用了protostuff來序列化,protostuff是目前最高效,節(jié)省空間的序列化方式     

3.在springboot啟動類上表明啟用緩存:@EnableCaching

4.定義緩存的名稱集合,統(tǒng)一管理緩存名稱

5.在需要使用緩存的查詢服務(wù)上使用:@Cacheable(keyGenerator = "keyGenerator")

6.在需要清理緩存的業(yè)務(wù)服務(wù)上使用:@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;
    }

    /**
     *  設(shè)置 redis 數(shù)據(jù)默認(rèn)過期時間
     *  設(shè)置@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生成策略
這里有一個不好的地方是我直接使用第一個參數(shù)作為key的標(biāo)示,是的程序中必須將id放在第一位,但這里只是一個事例,表明我們的key可以在這里進(jìn)行自定義。
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,這里可以根據(jù)業(yè)務(wù)類型自定義所有的key生成策略
     * @param target   被調(diào)用方法的類實例
     * @param method  方法的名稱
     * @param params 方法的參數(shù)
     * @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注解操作緩存

在使用的類(讀與寫的類都需要)上我們使用如下注解表明這個服務(wù)使用緩存的名稱是什么,也可以直接在方法上指明cacheName但是要寫多次。
@CacheConfig(cacheNames = RedisCacheName.KILL_PRODUCT)

在查詢的服務(wù)方法上添加如下注解表明該方法的返回值需要緩存。
@Cacheable(keyGenerator = "keyGenerator")

當(dāng)被緩存的數(shù)據(jù)發(fā)生改變,緩存需要被清理或者修改,這里使用如下注解清除指定key的緩存。
@CacheEvict(keyGenerator = "keyGenerator")

【redis客戶端查看緩存
使用redis-cli命令進(jìn)入redis(docker exec -it containerId  redis-cli)
輸入keys * 查看所有的緩存
我們可以看見緩存是按照cacheName + "::" + id 的方式生成的,而我們的key生成策略也是針對于生成id的那一部分。

【值得注意的一點

我們在使用緩存的時候應(yīng)該注意緩存的對象應(yīng)該處于哪一層,試想如果我的緩存在dao這一層,但是事務(wù)在service層,一個service方法包含了多個dao方法,如果在執(zhí)行service方法的時候,擁有緩存的dao方法成功,但是接下來的到方法失敗,那么我們的緩存就生效了,但是數(shù)據(jù)并沒有落庫,這就產(chǎn)生了數(shù)據(jù)不一致的問題。所以我們的緩存應(yīng)該在事務(wù)的更上層。事務(wù)是一個原子操作,所有的緩存,消息,這種非強(qiáng)一致性要求的操作,都應(yīng)該在事務(wù)成功提交后執(zhí)行。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/69084.html

相關(guān)文章

  • java并發(fā)編程學(xué)習(xí)21--基于springboot秒殺系統(tǒng)實現(xiàn)3--存儲過程

    摘要:但是經(jīng)過測試自身的是次秒,是一個相當(dāng)不錯的數(shù)據(jù),所以我們這里將事務(wù)直接交給,使用存儲過程來降低行級鎖的持有時間。存儲過程代碼使用存儲過程之前必須保證數(shù)據(jù)庫已經(jīng)創(chuàng)建了存儲過程。表示使用在存儲過程中替代最后需要還原回來。 【什么是存儲過程 所謂的存儲過程是指:是一組為了完成特定功能的SQL語句集,經(jīng)編譯后存儲在數(shù)據(jù)庫中,用戶通過指定存儲過程的名字并給定參數(shù)(如果該存儲過程帶有參數(shù))來調(diào)用執(zhí)...

    keithyau 評論0 收藏0
  • java并發(fā)編程學(xué)習(xí)19--基于springboot秒殺系統(tǒng)實現(xiàn)1--項目介紹

    摘要:當(dāng)秒殺日期尚未達(dá)到會提示用戶秒殺尚未開始當(dāng)用戶多次秒殺同一商品會提示用戶重復(fù)秒殺當(dāng)秒殺日期過期或者秒殺商品的庫存為零會提示用戶秒殺結(jié)束。 【秒殺系統(tǒng)業(yè)務(wù)分析 在秒殺系統(tǒng)當(dāng)中有兩個核心的表:秒殺商品(kill_product)與秒殺明細(xì)(kill_item),具體的邏輯是一個用戶秒殺商品的庫存減一,秒殺明細(xì)的記錄增加一條。這兩步作是處于同一事務(wù)之中。 當(dāng)秒殺日期尚未達(dá)到會提示用戶秒殺尚...

    CollinPeng 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<