<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      補(bǔ)習(xí)系列(14)-springboot redis 整合-數(shù)據(jù)讀寫

      一、簡介

      補(bǔ)習(xí)系列(A3)-springboot redis 與發(fā)布訂閱 一文中,我們介紹了使用 Redis 實現(xiàn)消息訂閱發(fā)布的機(jī)制,并且給出了一個真實用例。
      然而,絕大多數(shù)場景下 Redis 是作為緩存被使用的(這是其主要優(yōu)勢)。除此之外,由于Redis 提供了 AOF以及RDB兩種持久化機(jī)制,某些情況下也可以作為臨時數(shù)據(jù)庫使用。
      本次將介紹 SpringBoot 中如何使用 Redis 進(jìn)行緩存讀寫。

      Redis 的基本命令
      在學(xué)習(xí)之前,需要先了解一些Redis 的基本命令,可以參考這里
      http://www.redis.cn/

      二、SpringBoot Redis 讀寫

      A. 引入 spring-data-redis

      添加依賴

       <!-- redis -->
        <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-redis</artifactId>
         <version>${spring-boot.version}</version>
        </dependency>
      

      spring-boot-starter-redis在1.4版本已經(jīng)廢棄

      配置redis連接
      application.properties

      # redis 連接配置
      spring.redis.database=0 
      spring.redis.host=127.0.0.1
      spring.redis.password=
      spring.redis.port=6379
      spring.redis.ssl=false
      
      # 連接池最大數(shù)
      spring.redis.pool.max-active=10 
      # 空閑連接最大數(shù)
      spring.redis.pool.max-idle=10
      # 獲取連接最大等待時間(s)
      spring.redis.pool.max-wait=600000
      

      B. 序列化

      同樣,我們需要指定 JSON作為 Key/HashKey/Value的主要方式:

          /**
           * 序列化定制
           * 
           * @return
           */
          @Bean
          public Jackson2JsonRedisSerializer<Object> jackson2JsonSerializer() {
              Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
                      Object.class);
      
              // 初始化objectmapper
              ObjectMapper mapper = new ObjectMapper();
              mapper.setSerializationInclusion(Include.NON_NULL);
              mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
              jackson2JsonRedisSerializer.setObjectMapper(mapper);
              return jackson2JsonRedisSerializer;
          }
      
         /**
           * 操作模板
           * 
           * @param connectionFactory
           * @param jackson2JsonRedisSerializer
           * @return
           */
          @Bean
          public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory connectionFactory,
                  Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer) {
      
              RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
              template.setConnectionFactory(connectionFactory);
      
              // 設(shè)置key/hashkey序列化
              RedisSerializer<String> stringSerializer = new StringRedisSerializer();
              template.setKeySerializer(stringSerializer);
              template.setHashKeySerializer(stringSerializer);
      
              // 設(shè)置值序列化
              template.setValueSerializer(jackson2JsonRedisSerializer);
              template.setHashValueSerializer(jackson2JsonRedisSerializer);
              template.afterPropertiesSet();
      
              // template.setValueSerializer(new
              // GenericToStringSerializer<Object>(Object.class));
              return template;
          }
      

      Jackson2JsonRedisSerializer是Jackson轉(zhuǎn)換的橋接器;
      RedisTemplate是用于讀寫的主要操作類;

      C. 讀寫樣例

      首先定義一個Pet實體類

      public class RedisPet {
      
          private String name;
          private String type;
      ... ignore get set
      

      利用RedisTemplate封裝一層Repository,如下:

          @Repository
          public static class PetRepository {
      
              private static final String KEY = "Pets";
      
              @Autowired
              private RedisTemplate<String, Object> redisTemplate;
              private HashOperations<String, String, Object> hashOperations;
      
              @PostConstruct
              private void init() {
                  hashOperations = redisTemplate.opsForHash();
              }
      
              public void add(RedisPet pet) {
                  hashOperations.put(KEY, pet.getName(), pet);
              }
      
              public RedisPet find(String name) {
                  return (RedisPet) hashOperations.get(KEY, name);
              }
      
              public Map<String, Object> findAll() {
                  return hashOperations.entries(KEY);
              }
              
              public void clear() {
                  hashOperations.getOperations().delete(KEY);
              }
          }
      

      在**PetRepository **的實現(xiàn)中,我們利用Hash結(jié)構(gòu)來存儲 Pet信息(Pet.name是key)
      分別實現(xiàn)了添加(add)/查找(get)/清除(clear)等方法。

      最后,實現(xiàn)讀寫調(diào)用:

      
      @Service
      public class RedisDataOperation {
      
          private static final Logger logger = LoggerFactory.getLogger(RedisDataOperation.class);
      
          @Autowired
          private PetRepository petRepo;
      
      
          @PostConstruct
          public void start() {
      
              RedisPet pet1 = new RedisPet("Polly", "Bird");
              RedisPet pet2 = new RedisPet("Tom", "Cat");
      
              //寫入寵物信息
              petRepo.add(pet1);
              petRepo.add(pet2);
      
              //打印寵物信息
              logger.info("polly {}", JsonUtil.toJson(petRepo.find("Polly")));
              logger.info("pets  {}", JsonUtil.toJson(petRepo.findAll()));
      
              //清空
              petRepo.clear();
          }
      

      上面的代碼在應(yīng)用啟動時,會寫入兩個Pet信息,之后完成清理,控制臺輸出如下:

      RedisDataOperation : polly {"name":"Polly","type":"Bird"}
      RedisDataOperation : pets {"Tom":{"name":"Tom","type":"Cat"},"Polly":{"name":"Polly","type":"Bird"}}
      

      三、方法級緩存

      除了上面的RedisTemplate,spring-data-redis還提供了方法級緩存,
      就是將業(yè)務(wù)方法的執(zhí)行結(jié)果緩存起來,后面再次調(diào)用直接從緩存中取得結(jié)果返回。

      這種方式可以簡化緩存邏輯的代碼,比如配置類數(shù)據(jù)的讀取,通過方法注解就可以實現(xiàn),
      下面是一個樣例:

      /**
       * 方法級緩存樣例
       * 
       * @author atp
       *
       */
      @Service
      public class RedisCacheOperation {
      
          private static final Logger logger = LoggerFactory.getLogger(RedisCacheOperation.class);
      
          public static final String PREFIX = "pets:";
          public static final String WRAP_PREFIX = "'pets:'";
      
          /**
           * 當(dāng)結(jié)果不為空時緩存
           * 
           * @param name
           * @return
           */
          @Cacheable(value = "petCache", key = WRAP_PREFIX + "+#name", unless = "#result==null")
          public RedisPet getPet(String name) {
              logger.info("get pet {}", name);
              return new RedisPet(name, "Bird");
          }
      
          /**
           * 當(dāng)結(jié)果不為空時淘汰緩存
           * 
           * @param pet
           * @return
           */
          @CacheEvict(value = "petCache", key = WRAP_PREFIX + "+#pet.name", condition = "#result!=null")
          public RedisPet updatePet(RedisPet pet) {
              logger.info("update pet {}", pet.getName());
              return new RedisPet(pet.getName(), "Bird1");
          }
      
          /**
           * 當(dāng)結(jié)果為true時淘汰緩存
           * 
           * @param name
           * @return
           */
          @CacheEvict(value = "petCache", key = WRAP_PREFIX + "+#name", condition = "#result==true")
          public boolean deletePet(String name) {
              logger.info("delete pet {}", name);
              return true;
          }
      }
      

      涉及到幾個注解:

      注解 說明
      @Cachable 方法執(zhí)行結(jié)果緩存
      @CachePut 方法執(zhí)行結(jié)果緩存(強(qiáng)制)
      @CacheEvict 方法執(zhí)行時觸發(fā)刪除

      其中 @CachePut@Cachable 的區(qū)別在于,前者一定會執(zhí)行方法,并嘗試刷新緩存(條件滿足),
      而后者則是當(dāng)緩存中不存在時才會執(zhí)行方法并更新。
      注解中的屬性 key/condition 都支持通過 Spring EL 表達(dá)式來引用參數(shù)對象。

      啟用注解

      除了上面的代碼,我們還需要使用 @EnableCaching 啟用注解:

      @EnableCaching
      @Configuration
      public class RedisConfig {
      
          private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);
      
          /**
           * 緩存管理,支持方法級注解
           * 
           * @param template
           * @return
           */
          @Bean
          public RedisCacheManager cacheManager(RedisTemplate<String, Object> template) {
              RedisCacheManager redisCacheManager = new RedisCacheManager(template);
              // 默認(rèn)過期時間
              redisCacheManager.setDefaultExpiration(30 * 60 * 1000);
              return redisCacheManager;
          }
      

      當(dāng)@Cacheable 的key屬性為空時,框架會自動生成,格式類似:

      param1,param2,param3...
      

      如果希望修改默認(rèn)的行為,可以使用自定義的 KeyGenerator

          /**
           * 定制方法緩存的key生成策略
           *
           * @return
           */
          @Bean
          public KeyGenerator keyGenerator() {
              return new KeyGenerator() {
                  @Override
                  public Object generate(Object target, Method method, Object... args) {
                      StringBuilder sb = new StringBuilder();
                      sb.append(target.getClass().getName());
                      sb.append(method.getName());
      
                      for (Object arg : args) {
                          sb.append(arg.toString());
                      }
                      return sb.toString();
                  }
              };
          }
      

      單元測試

      使用一小段單元測試代碼來測試方法級緩存功能

      @RunWith(SpringRunner.class)
      @SpringBootTest(classes =BootSampleRedis.class)
      public class RedisCacheOperationTest {
      
          private static final Logger logger = LoggerFactory.getLogger(RedisCacheOperationTest.class);
      
          @Autowired
          private RedisTemplate<String, Object> redisTemplate;
      
          @Autowired
          private RedisCacheOperation operation;
      
          private RedisPet pet1 = new RedisPet("Polly", "Bird");
      
          @Test
          public void testGet() {
              operation.getPet(pet1.getName());
      
              Object object = redisTemplate.opsForValue().get(RedisCacheOperation.PREFIX + pet1.getName());
              logger.info(String.valueOf(object));
      
              assertNotNull(object);
          }
      
          @Test
          public void testUpdate() {
              operation.updatePet(pet1);
      
              Object object = redisTemplate.opsForValue().get(RedisCacheOperation.PREFIX + pet1.getName());
              logger.info(String.valueOf(object));
      
              assertNull(object);
          }
      
          @Test
          public void testDelete() {
              operation.getPet(pet1.getName());
      
              // delete cache
              operation.deletePet(pet1.getName());
      
              Object object = redisTemplate.opsForValue().get(RedisCacheOperation.PREFIX + pet1.getName());
              logger.info(String.valueOf(object));
      
              assertNull(object);
          }
      
      }
      

      四、連接池

      如果希望通過代碼來配置 Jedis 的連接池(熟悉的方式),可以聲明 JedisConnectionFactory 實現(xiàn):

          /**
           * 連接池配置
           *
           * @return
           */
          @Bean
          public JedisConnectionFactory jedisConnectionFactory() {
              JedisPoolConfig config = new JedisPoolConfig();
      
              // 最大連接
              config.setMaxTotal(10);
              // 最大空閑,與最大連接保持一致,可減少頻繁鍵鏈的開銷
              config.setMaxIdle(10);
              // 連接最大空閑時間
              config.setMinEvictableIdleTimeMillis(10 * 60 * 1000);
              // 獲取連接等待的最大時長
              config.setMaxWaitMillis(30000);
      
              // 進(jìn)行空閑連接檢測的時間間隔
              config.setTimeBetweenEvictionRunsMillis(30 * 1000);
              // 取消不必要的test,有利于性能提升
              config.setTestOnBorrow(false);![](https://img2018.cnblogs.com/blog/242916/201812/242916-20181206231048870-1133770725.png)
      
              config.setTestOnReturn(false);
      
              JedisConnectionFactory factory = new JedisConnectionFactory(config);
              factory.setHostName("127.0.0.1");
              factory.setPort(6379);
      
              logger.info("redis config init first");
              return factory;
          }
      

      更多配置可參考這里

      示例代碼可從 碼云gitee 下載。
      https://gitee.com/littleatp/springboot-samples/

      小結(jié)

      Redis 在大多數(shù)項目中的核心用途是緩存,spring-data-redis 為 SpringBoot 中集成 Redis 讀寫的封裝。
      除了 RedisTemplate之外,還實現(xiàn)了方法級的緩存注解,一定程度上簡化了業(yè)務(wù)的使用。
      Redis 在分布式系統(tǒng)中的應(yīng)用場景有很多,后續(xù)有機(jī)會將進(jìn)行更多的探討。

      歡迎繼續(xù)關(guān)注"美碼師的補(bǔ)習(xí)系列-springboot篇" ,期待更多精彩內(nèi)容-

      posted @ 2018-12-06 23:12  美碼師  閱讀(2218)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 中文字幕人妻av12| 亚洲精品成人福利网站| 国产99久久亚洲综合精品西瓜tv | 国产一级精品在线免费看| av色国产色拍| 亚洲国产精品综合久久20| 久久精品第九区免费观看| 久久久精品2019中文字幕之3| 亚洲欧美精品在线| 宝贝腿开大点我添添公口述视频| 中文字幕人妻有码久视频| 四虎在线成人免费观看| 亚洲一卡2卡三卡四卡精品| 国产人妻高清国产拍精品| 在线看国产精品三级在线| 思思久99久女女精品| 中文字幕无码免费不卡视频| 一本精品99久久精品77| 少妇激情一区二区三区视频小说| 亚洲十八禁一区二区三区| 国产精品自在拍首页视频8| 一边添奶一边添p好爽视频| 国产亚洲一区二区三不卡| 日韩理伦片一区二区三区| 日韩精品一区二区三区激情视频| 亚洲av久久精品狠狠爱av| 夜夜春久久天堂亚洲精品| 人妻少妇精品性色av蜜桃| 国产午夜福利视频合集| 九九热精品免费在线视频| 精品乱码一区二区三四五区| 88国产精品视频一区二区三区| 亚洲色大成网站www永久一区| 99久久精品费精品国产一区二| 亚洲色婷婷久久精品av蜜桃久久| 国产精品一区二区久久岳| 国产成人午夜福利院| 日土县| 国产偷国产偷亚洲高清人| VA在线看国产免费| 久久精品免视看国产成人|