激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - springboot中使用redis由淺入深解析

springboot中使用redis由淺入深解析

2021-02-05 11:58nfcm Java教程

這篇文章主要由淺入深為大家介紹了springboot中使用redis的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下

正文

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

redis連接工廠類

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

?
1
2
3
4
<dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>

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

?
1
2
3
4
5
6
7
8
9
10
11
@configuration
public class redisconfig {
  @bean
  public redisconnectionfactory rediscf(){
    //如果什么參數都不設置,默認連接本地6379端口
    jedisconnectionfactory factory = new jedisconnectionfactory();
    factory.setport(6379);
    factory.sethostname("localhost");
    return factory;
  }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@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())));
  }
 
}

輸出結果 :world,說明已經成功獲取到連接,并且往redis獲取添加數據,

template(模版)

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

spring data redis提供了兩個模板:
  redistemplate
  stringredistemplate

首先我們先創建一個redistemplate模板類,類型的key是string類型,value是object類型(如果key和value都是string類型,建議使用stringredistemplate)

?
1
2
3
4
5
6
7
8
@bean
public redistemplate redistemplate(redisconnectionfactory factory){
  //創建一個模板類
  redistemplate<string, object> template = new redistemplate<string, object>();
  //將剛才的redis連接工廠設置到模板類中
  template.setconnectionfactory(factory);
  return template;
}

單元測試

?
1
2
3
4
5
6
7
8
@autowired
  redistemplate<string, object> template;
  
  @test
  public void testredistemplate(){
    template.opsforvalue().set("key1", "value1");
    system.out.println(template.opsforvalue().get("key1"));
  }

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@test
public void testredistemplatelist(){
 
  pruduct prud = new pruduct(1, "洗發水", "100ml");
  pruduct prud2 = new pruduct(2, "洗面奶", "200ml");
  //依次從尾部添加元素
  template.opsforlist().rightpush("pruduct", prud);
  template.opsforlist().rightpush("pruduct", prud);
  //查詢索引0到商品總數-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("產品數量:"+template.opsforlist().size("pruduct"));
  
}

key和value序列化

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

generictostringserializer:使用spring轉換服務進行序列化;
jacksonjsonredisserializer:使用jackson 1,將對象序列化為json;
jackson2jsonredisserializer:使用jackson 2,將對象序列化為json;
jdkserializationredisserializer:使用java序列化;
oxmserializer:使用spring o/x映射的編排器和解排器(marshaler和unmarshaler)實現序列化,用于xml序列化;
stringredisserializer:序列化string類型的key和value。

redistemplate會默認使用jdkserializationredisserializer,這意味著key和value都會通過java進行序列化。stringredistemplate默認會使用stringredisserializer

例如,假設當使用redistemplate的時候,我們希望將product類型的value序列化為json,而key是string類型。redistemplate的setkeyserializer()和setvalueserializer()方法就需要如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@bean
  public redistemplate redistemplate(redisconnectionfactory factory) {
    // 創建一個模板類
    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轉對象類,不設置默認的會將json轉成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緩存某個方法

申明緩存管理器

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

首先在我們的redisconfig這個類上加上@enablecaching這個注解。

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

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

?
1
2
3
4
5
6
7
8
9
10
/**
   * 申明緩存管理器,會創建一個切面(aspect)并觸發spring緩存注解的切點(pointcut)
   * 根據類或者方法所使用的注解以及緩存的狀態,這個切面會從緩存中獲取數據,將數據添加到緩存之中或者從緩存中移除某個值
   
   * @return
   */
  @bean
  public rediscachemanager cachemanager(redistemplate redistemplate) {
    return new rediscachemanager(redistemplate);
  }

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

  • simplecachemanager
  • noopcachemanager
  • concurrentmapcachemanager
  • compositecachemanager
  • ehcachecachemanager

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

添加緩存

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

?
1
2
3
4
5
6
@requestmapping("/getprud")
  @cacheable("prudcache")
  public pruduct getprud(@requestparam(required=true)string id){
    system.out.println("如果第二次沒有走到這里說明緩存被添加了");
    return pruductdao.getprud(integer.parseint(id));
  }

發現打印的這段話只被打印一次,說明在走到這個方法的時候觸發了一個切面,并且查找返回緩存中的數據。

當然@cacheable注解也可以放到這個dao層的方法里面,但是這里會報一個錯,integer無法轉成string,因為我們dao層方法的參數類型是int,而redistemplate的key類型是string,這里是要注意的。

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

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

springboot中使用redis由淺入深解析

刪除緩存

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

?
1
2
3
4
5
@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類型,所以需要將數字轉化成string類型)

?
1
2
3
4
5
@requestmapping("/saveprud")
@cacheput(value="prudsavecache",key="#result.id +''")
public pruduct saveprud(pruduct prud){
  return prud;
}

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

springboot中使用redis由淺入深解析

 條件化緩存

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

@cacheable和@cacheput提供了兩個屬性用以實現條件化緩存:unless和condition,這兩個屬性都接受一個spel表達式。如果unless屬性的spel表達式計算結
果為true,那么緩存方法返回的數據就不會放到緩存中。與之類似,如果condition屬性的spel表達式計算結果為false,那么對于這個方法緩存就會被禁用掉

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

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

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

?
1
2
3
4
5
6
7
8
@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字符串,則不進行緩存。

總結demo:

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

?
1
2
3
4
5
6
@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

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@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();
      }
    };
  
  /**
   * 申明緩存管理器,會創建一個切面(aspect)并觸發spring緩存注解的切點(pointcut)
   * 根據類或者方法所使用的注解以及緩存的狀態,這個切面會從緩存中獲取數據,將數據添加到緩存之中或者從緩存中移除某個值
   
   * @return
   */
  @bean
  public rediscachemanager cachemanager(redistemplate redistemplate) {
    return new rediscachemanager(redistemplate);
  }
 
 
  @bean
  @primary
  public redistemplate redistemplate(redisconnectionfactory factory) {
    // 創建一個模板類
    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轉對象類,不設置默認的會將json轉成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下配置

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# redis (redisproperties)
# redis數據庫索引(默認為0
spring.redis.database=0
# redis服務器地址
spring.redis.host=127.0.0.1
# redis服務器連接端口
spring.redis.port=6379
# redis服務器連接密碼(默認為空)
spring.redis.password=
# 連接池最大連接數(使用負值表示沒有限制)
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

大家發現我們并沒有注冊redisconnectionfactory,那是因為spring默認幫我們讀取application.properties文件并且注冊了一個factorybean

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

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

本文代碼github地址

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.cnblogs.com/nfcm/p/7833032.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 99在线热视频 | 久久午夜国产 | 性少妇videosexfreexx入片 | 98国内自拍在线视频 | 黄色欧美精品 | 国产在线精品一区二区三区 | av影院在线播放 | 成人毛片网 | 欧美精品久久久久久久久久 | 一区二区三区日本在线观看 | 成年免费大片黄在线观看岛国 | 黄色av.com | 午夜爽爽爽男女免费观看hd | 久久色在线 | 久色网站| 视频www| 看免费黄色大片 | 日本中文字幕久久 | 国产精品久久久久无码av | h色网站在线观看 | 亚洲一区在线国产 | 福利在线免费 | 日韩欧美精品电影 | 欧美精品成人一区二区三区四区 | 久色免费视频 | av免费提供 | 午夜男人在线观看 | 黄色毛片视频在线观看 | 成年免费视频黄网站在线观看 | 91精品国产91| 午夜男人在线观看 | 国产精品毛片va一区二区三区 | 男女羞羞视频 | 欧美精品亚洲人成在线观看 | 精品一区二区三区免费毛片 | 日韩在线毛片 | 欧美 国产 亚洲 卡通 综合 | 国产精品一区久久久久 | 精品在线免费播放 | av电影在线免费观看 | 欧美一级淫片007 |