最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot中使用redis由淺入深解析

 更新時間:2017年11月15日 14:05:28   作者:nfcm  
這篇文章主要由淺入深為大家介紹了springboot中使用redis的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下

正文

很多時候,我們會在springboot中配置redis,但是就那么幾個配置就配好了,沒辦法知道為什么,這里就詳細的講解一下
這里假設已經(jīng)成功創(chuàng)建了一個springboot項目。

redis連接工廠類

第一步,需要加上springboot的redis jar包

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

然后我們寫一個配置類,創(chuàng)建了一個redis連接的工廠的spring bean。(Redis連接工廠會生成到Redis數(shù)據(jù)庫服務器的連接)

@Configuration
public class RedisConfig {
  @Bean
  public RedisConnectionFactory redisCF(){
    //如果什么參數(shù)都不設置,默認連接本地6379端口
    JedisConnectionFactory factory = new JedisConnectionFactory();
    factory.setPort(6379);
    factory.setHostName("localhost");
    return factory;
  }
}

單元測試,看看這個工廠方法的使用

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisTest {
  
  @Autowired
  RedisConnectionFactory factory;
    
  @Test
  public void testRedis(){
    //得到一個連接
    RedisConnection conn = factory.getConnection();
    conn.set("hello".getBytes(), "world".getBytes());
    System.out.println(new String(conn.get("hello".getBytes())));
  }

}

輸出結(jié)果 :world,說明已經(jīng)成功獲取到連接,并且往redis獲取添加數(shù)據(jù),

template(模版)

但是我們發(fā)現(xiàn)每次添加的key和value都是byte數(shù)組類型(使用很麻煩),于是spring為我們帶來了redis template(模版)

Spring Data Redis提供了兩個模板:
  RedisTemplate
  StringRedisTemplate

首先我們先創(chuàng)建一個RedisTemplate模板類,類型的key是String類型,value是Object類型(如果key和value都是String類型,建議使用StringRedisTemplate)

  @Bean
  public RedisTemplate redisTemplate(RedisConnectionFactory factory){
    //創(chuàng)建一個模板類
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    //將剛才的redis連接工廠設置到模板類中
    template.setConnectionFactory(factory);
    return template;
  }

單元測試

@Autowired  
  RedisTemplate<String, Object> template;
  
  @Test
  public void testRedisTemplate(){
    template.opsForValue().set("key1", "value1");
    System.out.println(template.opsForValue().get("key1"));
  }

得到結(jié)果輸出value1,是不是很方便了呢。

 如果是操作集合呢,也很方便的哈。

  @Test
  public void testRedisTemplateList(){
  
    Pruduct prud = new Pruduct(1, "洗發(fā)水", "100ml");
    Pruduct prud2 = new Pruduct(2, "洗面奶", "200ml");
    //依次從尾部添加元素
    template.opsForList().rightPush("pruduct", prud);
    template.opsForList().rightPush("pruduct", prud);
    //查詢索引0到商品總數(shù)-1索引(也就是查出所有的商品)
    List<Object> prodList = template.opsForList().range("pruduct", 0,template.opsForList().size("pruduct")-1);
    for(Object obj:prodList){
      System.out.println((Pruduct)obj);
    }
    System.out.println("產(chǎn)品數(shù)量:"+template.opsForList().size("pruduct"));
    
  }

key和value序列化

當保存一條數(shù)據(jù)的時候,key和value都要被序列化成json數(shù)據(jù),取出來的時候被序列化成對象,key和value都會使用序列化器進行序列化,spring data redis提供多個序列化器

GenericToStringSerializer:使用Spring轉(zhuǎn)換服務進行序列化;
JacksonJsonRedisSerializer:使用Jackson 1,將對象序列化為JSON;
Jackson2JsonRedisSerializer:使用Jackson 2,將對象序列化為JSON;
JdkSerializationRedisSerializer:使用Java序列化;
OxmSerializer:使用Spring O/X映射的編排器和解排器(marshaler和unmarshaler)實現(xiàn)序列化,用于XML序列化;
StringRedisSerializer:序列化String類型的key和value。

RedisTemplate會默認使用JdkSerializationRedisSerializer,這意味著key和value都會通過Java進行序列化。StringRedisTemplate默認會使用StringRedisSerializer

例如,假設當使用RedisTemplate的時候,我們希望將Product類型的value序列化為JSON,而key是String類型。RedisTemplate的setKeySerializer()和setValueSerializer()方法就需要如下所示:

@Bean
  public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
    // 創(chuàng)建一個模板類
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    // 將剛才的redis連接工廠設置到模板類中
    template.setConnectionFactory(factory);
    // 設置key的序列化器
    template.setKeySerializer(new StringRedisSerializer());
    // 設置value的序列化器
    //使用Jackson 2,將對象序列化為JSON
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    //json轉(zhuǎn)對象類,不設置默認的會將json轉(zhuǎn)成hashmap
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    template.setValueSerializer(jackson2JsonRedisSerializer);

    return template;
  }

到這里,大家肯定會對springboot使用redis有了簡單的了解。

springboot緩存某個方法

申明緩存管理器

在某些時候,我們可能有這樣的需求,用戶登錄的時候,我們會從數(shù)據(jù)庫中讀取用戶所有的權限,部門等信息。而且每次刷新頁面都需要判斷該用戶有沒有這個權限,如果不停的從數(shù)據(jù)庫中讀并且計算,是非常耗性能的,所以我們這個時候就要用到了springboot為我們帶來的緩存管理器

首先在我們的RedisConfig這個類上加上@EnableCaching這個注解。

這個注解會被spring發(fā)現(xiàn),并且會創(chuàng)建一個切面(aspect) 并觸發(fā)Spring緩存注解的切點(pointcut) 。 根據(jù)所使用的注解以及緩存的狀態(tài), 這個切面會從緩存中獲取數(shù)據(jù), 將數(shù)據(jù)添加到緩存之中或者從緩存中移除某個值。 

接下來我們需要申明一個緩存管理器的bean,這個作用就是@EnableCaching這個切面在新增緩存或者刪除緩存的時候會調(diào)用這個緩存管理器的方法

/**
   * 申明緩存管理器,會創(chuàng)建一個切面(aspect)并觸發(fā)Spring緩存注解的切點(pointcut)
   * 根據(jù)類或者方法所使用的注解以及緩存的狀態(tài),這個切面會從緩存中獲取數(shù)據(jù),將數(shù)據(jù)添加到緩存之中或者從緩存中移除某個值
   
   * @return
   */
  @Bean
  public RedisCacheManager cacheManager(RedisTemplate redisTemplate) {
    return new RedisCacheManager(redisTemplate);
  }

 當然,緩存管理器除了RedisCacheManager還有一些其他的。例如

  • SimpleCacheManager
  • NoOpCacheManager
  • ConcurrentMapCacheManager
  • CompositeCacheManager
  • EhCacheCacheManager

ConcurrentMapCacheManager,這個簡單的緩存管理器使用java.util.concurrent.ConcurrentHashMap作為其緩存存儲。它非常簡單,因此對于開發(fā)、測試或基礎的應用來講,這是一個很不錯的選擇.

添加緩存

接下來我們在controller層的方法內(nèi)加上注解,然后啟動我們的項目。

@RequestMapping("/getPrud")
  @Cacheable("prudCache")
  public Pruduct getPrud(@RequestParam(required=true)String id){
    System.out.println("如果第二次沒有走到這里說明緩存被添加了");
    return pruductDao.getPrud(Integer.parseInt(id));
  }

發(fā)現(xiàn)打印的這段話只被打印一次,說明在走到這個方法的時候觸發(fā)了一個切面,并且查找返回緩存中的數(shù)據(jù)。

當然@Cacheable注解也可以放到這個dao層的方法里面,但是這里會報一個錯,Integer無法轉(zhuǎn)成String,因為我們dao層方法的參數(shù)類型是int,而RedisTemplate的key類型是String,這里是要注意的。

打開redis的客戶端發(fā)現(xiàn)redis對應的key就是我們的參數(shù)1,這個時候就會出問題,比如說我在其他要緩存的方法的參數(shù)也是1,就會重復。后面我們會將自定義這個key的值。

除了@Cacheable添加緩存外,springboot還為我們帶了了其他幾個注解

刪除緩存

在delete的時候用@CacheEvict清楚這條緩存。

  @RequestMapping("/deletePrud")
  @CacheEvict("pruddeleteCache")
  public String deletePrud(@RequestParam(required=true)String id){
    return "SUCCESS";
  }

@CachePut將這個方法的返回值放到緩存,如果我們放一個Pruduct對象,他會將這個對象作為key,這顯然不是我們想要的。這個時候就需要自定義我們的key。

自定義key

@Cacheable和@CachePut都有一個名為key屬性,這個屬性能夠替換默認的key,它是通過一個表達式(Spel表達式,spring提供的,很簡單)計算得到的。

例如下面的就是將返回對象的id當作key來存儲(但是Pruduct的id是int類型,所以需要將數(shù)字轉(zhuǎn)化成String類型)

  @RequestMapping("/savePrud")
  @CachePut(value="prudsaveCache",key="#result.id +''")
  public Pruduct savePrud(Pruduct prud){
    return prud;
  }

另外除了#result是代表函數(shù)的返回值,spring還為我們帶來了其他的一些元數(shù)據(jù)

 條件化緩存

通過為方法添加Spring的緩存注解,Spring就會圍繞著這個方法創(chuàng)建一個緩存切面。但是,在有些場景下我們可能希望將緩存功能關閉。

@Cacheable和@CachePut提供了兩個屬性用以實現(xiàn)條件化緩存:unless和condition,這兩個屬性都接受一個SpEL表達式。如果unless屬性的SpEL表達式計算結(jié)
果為true,那么緩存方法返回的數(shù)據(jù)就不會放到緩存中。與之類似,如果condition屬性的SpEL表達式計算結(jié)果為false,那么對于這個方法緩存就會被禁用掉

表面上來看,unless和condition屬性做的是相同的事情。但是,這里有一點細微的差別。

unless屬性只能阻止將對象放進緩存,但是在這個方法調(diào)用的時候,依然會去緩存中進行查找,如果找到了匹配的值,就會返回找到的值。

與之不同,如果condition的表達式計算結(jié)果為false,那么在這個方法調(diào)用的過程中,緩存是被禁用的。就是說,不會去緩存進行查找,同時返回值也不會放進緩存中。

  @RequestMapping("/getPrud2")
  @CachePut(value ="prudCache",unless="#result.desc.contains('nocache')")
  public Pruduct getPrud2(@RequestParam(required=true)String id){
    System.out.println("如果走到這里說明,說明緩存沒有生效!");
    Pruduct p = new Pruduct(Integer.parseInt(id), "name_nocache"+id, "nocache");
    return p;
  }
  

上面的代碼中,如果返回的對象desc中包含nocache字符串,則不進行緩存。

總結(jié)demo:

將類名方法名和pruduct的id作為key

@RequestMapping("/getPrud3")
  @Cacheable(value ="prudCache",key="#root.targetClass.getName() + #root.methodName + #id")
  public Pruduct getPrud3(@RequestParam(required=true)String id){
    System.out.println("如果第二次沒有走到這里說明緩存被添加了");
    return pruductDao.getPrud(Integer.parseInt(id));
  }

最后注意

#result 方法返回值不能用在@Cacheable上,只能用在@CachePut

springboot配置升級簡單化

當然上面的配置只是為了了解原理的哈,實際上我們使用會更簡單點。我們重寫了RedisConfig

@Configuration
@EnableCaching//開啟緩存
public class RedisConfig extends CachingConfigurerSupport {

  @Bean
  public KeyGenerator keyGenerator() {
    return new KeyGenerator() {
      @Override
      public Object generate(Object target, Method method, Object... params) {
        StringBuilder sb = new StringBuilder();
        sb.append(target.getClass().getName());
        sb.append(method.getName());
        for (Object obj : params) {
          sb.append(obj.toString());
        }
        return sb.toString();
      }
    };
  }  
  /**
   * 申明緩存管理器,會創(chuàng)建一個切面(aspect)并觸發(fā)Spring緩存注解的切點(pointcut)
   * 根據(jù)類或者方法所使用的注解以及緩存的狀態(tài),這個切面會從緩存中獲取數(shù)據(jù),將數(shù)據(jù)添加到緩存之中或者從緩存中移除某個值
   
   * @return
   */
  @Bean
  public RedisCacheManager cacheManager(RedisTemplate redisTemplate) {
    return new RedisCacheManager(redisTemplate);
  }


  @Bean
  @Primary
  public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
    // 創(chuàng)建一個模板類
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    // 將剛才的redis連接工廠設置到模板類中
    template.setConnectionFactory(factory);
    // 設置key的序列化器
    template.setKeySerializer(new StringRedisSerializer());
    // 設置value的序列化器
    //使用Jackson 2,將對象序列化為JSON
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    //json轉(zhuǎn)對象類,不設置默認的會將json轉(zhuǎn)成hashmap
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    template.setValueSerializer(jackson2JsonRedisSerializer);

    return template;
  }

}

然后在resources下的application.properties下配置

# REDIS (RedisProperties)
# Redis數(shù)據(jù)庫索引(默認為0)
spring.redis.database=0 
# Redis服務器地址
spring.redis.host=127.0.0.1
# Redis服務器連接端口
spring.redis.port=6379 
# Redis服務器連接密碼(默認為空)
spring.redis.password=
# 連接池最大連接數(shù)(使用負值表示沒有限制)
spring.redis.pool.max-active=8 
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1 
# 連接池中的最大空閑連接
spring.redis.pool.max-idle=8 
# 連接池中的最小空閑連接
spring.redis.pool.min-idle=0 
# 連接超時時間(毫秒)
spring.redis.timeout=0

大家發(fā)現(xiàn)我們并沒有注冊RedisConnectionFactory,那是因為spring默認幫我們讀取application.properties文件并且注冊了一個factorybean

keyGenerator方法幫我們注冊了一個key的生成規(guī)則,就不用我們寫spel表達式了,根據(jù)反射的原理讀取類名+方法名+參數(shù)。但是我們有時候還是需要結(jié)合spel的。

然后在controller上加上@Cacheable("cachename"),之后就可以在redis看到保存了并且key的值是keyGenerator生成的名字

本文代碼github地址

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • maven配置阿里云倉庫的實現(xiàn)方法

    maven配置阿里云倉庫的實現(xiàn)方法

    本文主要介紹了maven配置阿里云倉庫的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 解決Lombok注解不起作用的問題

    解決Lombok注解不起作用的問題

    這篇文章主要介紹了解決Lombok注解不起作用的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • java語言自行實現(xiàn)ULID過程底層原理詳解

    java語言自行實現(xiàn)ULID過程底層原理詳解

    這篇文章主要為大家介紹了java語言自行實現(xiàn)ULID過程底層原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • java中HashMap的7種遍歷方式與性能分析

    java中HashMap的7種遍歷方式與性能分析

    本文主要介紹了java中HashMap的7種遍歷方式與性能分析,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • Java中replace與replaceAll的區(qū)別與測試

    Java中replace與replaceAll的區(qū)別與測試

    replace和replaceAll是JAVA中常用的替換字符的方法,下面這篇文章主要給大家介紹了關于Java中replace與replaceAll的區(qū)別與測試,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • 通過實例解析java String不可變性

    通過實例解析java String不可變性

    這篇文章主要介紹了通過實例解析java String不可變性,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • 深入了解Java設計模式之職責鏈模式

    深入了解Java設計模式之職責鏈模式

    Java設計模式中有很多種類別,例如單例模式、裝飾模式、觀察者模式等。本文將為大家詳細介紹其中的職責鏈模式,感興趣的可以了解一下
    2022-09-09
  • Java實現(xiàn)在線SQL編程最新完整版

    Java實現(xiàn)在線SQL編程最新完整版

    這篇文章主要介紹了Java實現(xiàn)在線SQL編程,在使用JDBC來進行數(shù)據(jù)庫的操作,在使用時由于對其方法并不是全部了解,所以需要邊看源碼邊改善功能,感興趣的朋友跟隨小編一起看看吧
    2022-06-06
  • Java實現(xiàn)動態(tài)模擬時鐘

    Java實現(xiàn)動態(tài)模擬時鐘

    這篇文章主要為大家詳細介紹了Java實現(xiàn)動態(tài)模擬時鐘,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • idea創(chuàng)建maven父子工程導致子工程無法導入父工程依賴

    idea創(chuàng)建maven父子工程導致子工程無法導入父工程依賴

    創(chuàng)建maven父子工程時遇到一個問題,本文主要介紹了idea創(chuàng)建maven父子工程導致子工程無法導入父工程依賴,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04

最新評論

罗山县| 永德县| 从江县| 丰都县| 柘城县| 邮箱| 荔波县| 兰考县| 涟水县| 武胜县| 延津县| 攀枝花市| 灌南县| 凤翔县| 五大连池市| 桦南县| 临江市| 方正县| 盐城市| 静安区| 盘锦市| 右玉县| 靖远县| 普兰县| 东安县| 杭州市| 临夏县| 台前县| 新营市| 绥宁县| 邳州市| 凌云县| 牡丹江市| 清原| 文登市| 延边| 深圳市| 大庆市| 南雄市| 元谋县| 湘西|