1. 程式人生 > 程式設計 >Spring框架接入單機Redis兩種實現方式解析

Spring框架接入單機Redis兩種實現方式解析

1、Redis的簡單介紹

1)Redis 是一個開源(BSD許可)的,記憶體中的資料結構儲存系統,它可以用作資料庫、快取和訊息中介軟體。 它支援多種型別的資料結構,如 字串(strings), 雜湊(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 這些資料型別都支援push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。Redis 內建了 複製(replication),LUA指令碼(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁碟持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分割槽(Cluster)提供高可用性(high availability)。Redis 是完全開源免費的,遵守BSD協議,是一個高效能的key-value資料庫。

2)Redis的記憶體管理機制:

在Redis中,並不是所有的資料都一直儲存在記憶體中的。當實體記憶體用完時,Redis可以將一些很久沒用到的value交換到磁碟。Redis只會快取所有的key的資訊,如果Redis發現記憶體的使用量超過了某一個閥值,將觸發swap的操作,Redis根據“swappability = age*log(size_in_memory)”計算出哪些key對應的value需要swap到磁碟。然後再將這些key對應的value持久化到磁碟中,同時在記憶體中清除。這種特性使得Redis可以保持超過其機器本身記憶體大小的資料。

3)Redis效能和叢集管理:

Redis雖然支援資料的持久化,但是全記憶體畢竟才是其高效能的本質。作為基於記憶體的儲存系統來說,機器實體記憶體的大小就是系統能夠容納的最大資料量。如果需要處理的資料量超過了單臺機器的實體記憶體大小,就需要構建分散式叢集來擴充套件儲存能力。Redis更偏向於在伺服器端構建分散式儲存。

4)Redis 同其他 key - value 快取資料庫比較具有以下

  • Redis支援資料的持久化,可以將記憶體中的資料儲存在磁碟中,重啟的時候可以再次載入進行使用。
  • Redis不僅僅支援簡單的key-value型別的資料,同時還提供list,set,zset,hash等資料結構的儲存。
  • Redis支援資料的備份,即master-slave模式的資料備份。

5)Redis優勢

  • .效能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
  • .豐富的資料型別 – Redis支援二進位制案例的 Strings,Lists,Hashes,Sets 及 Ordered Sets 資料型別操作。
  • .原子 – Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支援事務,即原子性,通過MULTI和EXEC指令包起來。
  • .豐富的特性 – Redis還支援 publish/subscribe,通知,key 過期等等特性。
  • .Redis執行在記憶體中但是可以持久化到磁碟,所以在對不同資料集進行高速讀寫時需要權衡記憶體,因為資料量不能大於硬體記憶體。在記憶體資料庫方面的另一個優點是,相比在磁碟上相同的複雜的資料結構,在記憶體中操作起來非常簡單,這樣Redis可以做很多內部複雜性很強的事情。同時,在磁碟格式方面他們是緊湊的以追加的方式產生的,因為他們並不需要進行隨機訪問。

2、spring框架中接入redis的兩種方式:

步驟1:引入相關依賴

<!--使用jedis 需要引入 commons-pool 的依賴,否則Jedis會例項化失敗-->
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.7.1</version>
    </dependency>
    <dependency>
      <groupId>commons-pool</groupId>
      <artifactId>commons-pool</artifactId>
      <version>1.5.6</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>1.6.2.RELEASE</version>
    </dependency>

    <!-- redis中 如果儲存的是Map<String,Object>需要匯入jackson相關的包,儲存的時候使用json序列化器儲存。如果不匯入jackson的包會報錯。 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.5.1</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.5.1</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.5.1</version>
    </dependency>

步驟2:Redis相關屬性檔案:redis.properties

#訪問地址
redis.host=127.0.0.1
#訪問埠
redis.port=6379
#注意,如果沒有password,此處不設定值,但這一項要保留
redis.password=@redisLearn

#最大空閒數,資料庫連線的最大空閒時間。超過空閒時間,資料庫連線將被標記為不可用,然後被釋放。設為0表示無限制。
redis.maxIdle=300
#連線池的最大資料庫連線數。設為0表示無限制
redis.maxActive=600

#最大建立連線等待時間。如果超過此時間將接到異常。設為-1表示無限制。
redis.maxWait=1000

#在borrow一個jedis例項時,是否提前進行alidate操作;如果為true,則得到的jedis例項均是可用的;
redis.testOnBorrow=true

#客戶端連線超時時間
redis.timeout=30000

#可用資料庫數
redis.database = 0

步驟3:Spring中引入Redis配置、及呼叫例項(方式1和方式2選擇其中一種進行配置)

  方式1:通過spring-data-redis工具實現對Redis的操作 spring-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
">

  <!-- 連線池基本引數配置,類似資料庫連線池 -->
  <context:property-placeholder location="classpath:conf/redis.properties" ignore-unresolvable="true" />

  <!-- redis連線池 -->
  <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="${redis.maxActive}" />
    <property name="maxIdle" value="${redis.maxIdle}" />
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />
  </bean>

  <!-- 連線池配置,類似資料庫連線池 -->
  <bean id="jedisConnectionFactory"
     class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="${redis.host}"></property>
    <property name="port" value="${redis.port}"></property>
    <!-- <property name="password" value="${redis總結.pass}"></property> -->
    <property name="poolConfig" ref="poolConfig"></property>
  </bean>

  <!--redis操作模版,使用該物件可以操作redis -->
  <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <!--如果不配置Serializer,那麼儲存的時候預設使用String,如果用User型別儲存,那麼會提示錯誤User can't cast to String!! -->
    <property name="keySerializer" >
      <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
    </property>
    <property name="valueSerializer" >
      <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
    </property>
    <property name="hashKeySerializer">
      <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    </property>
    <property name="hashValueSerializer">
      <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
    </property>
    <!--開啟事務 -->
    <property name="enableTransactionSupport" value="true"></property>
  </bean >

</beans>

方式2:通過jedis客戶端工具實現對Redis的操作 spring-jedis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
">

  <!-- 連線池基本引數配置,類似資料庫連線池 -->
  <context:property-placeholder location="classpath:conf/redis.properties" ignore-unresolvable="true" />

  <!-- redis連線池 -->
  <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="${redis.maxActive}" />
    <property name="maxIdle" value="${redis.maxIdle}" />
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />
  </bean>

  <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
    <constructor-arg name="poolConfig" ref="poolConfig" />
    <constructor-arg name="host" value="${redis.host}" />
    <constructor-arg name="port" value="${redis.port}" type="int" />
    <constructor-arg name="timeout" value="${redis.timeout}" type="int" />
    <constructor-arg name="password" value="${redis.password}" />
    <constructor-arg name="database" value="${redis.database}" type="int" />
  </bean>

</beans>

步驟4:在web.xml中進行 進行 servletContext上下文讀取

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
   <!--classpath:spring/spring-redis.xml,-->
    classpath:spring/spring-jedis.xml,</param-value>
 </context-param>

步驟5:接入測試

方式1:測試程式碼

@Controller
@RequestMapping("/redis")
public class RedisController {

@Resource(name="redisTemplate") 
  private RedisTemplate redisTemplate;

  @RequestMapping("/operate.do")
  @ResponseBody
  public Map springRedisDo() {
    Map result=new HashMap();

    // stringRedisTemplate的操作
    // String讀寫
    redisTemplate.delete("myStrKey");
    redisTemplate.opsForValue().set("myStrKey","strValue");
    String strValue= (String) redisTemplate.opsForValue().get("myStrKey");
    result.put("strValue",strValue);

    // List讀寫
    redisTemplate.delete("myListKey");
    redisTemplate.opsForList().rightPush("myListKey","listValue1");
    redisTemplate.opsForList().rightPush("myListKey","listValue2");
    redisTemplate.opsForList().leftPush("myListKey","listValue3");
    List<String> myListKeyValues = redisTemplate.opsForList().range("myListKey",-1);
    for (String s : myListKeyValues) {
      System.out.println("myListKey資料元素>>>"+s);
    }
    result.put("myListKeyValues",myListKeyValues);

    // Set讀寫
    redisTemplate.delete("mySet");
    redisTemplate.opsForSet().add("mySetKey","setValue1");
    redisTemplate.opsForSet().add("mySetKey","setValue2");
    redisTemplate.opsForSet().add("mySetKey","setValue3");
    redisTemplate.opsForSet().add("mySetKey","setValue3");
    Set<String> setValues = redisTemplate.opsForSet().members("mySetKey");
    for (String s : setValues) {
      System.out.println("mySetKey資料元素>>>"+s);
    }
    result.put("setValues",setValues);

    // Hash讀寫
    redisTemplate.delete("myHashKey");
    redisTemplate.opsForHash().put("myHashKey","BJ","北京");
    redisTemplate.opsForHash().put("myHashKey","SH","上海");
    redisTemplate.opsForHash().put("myHashKey","TJ","天津");
    Map<String,String> hashValues = redisTemplate.opsForHash().entries("myHashKey");
    List myHashList= redisTemplate.opsForHash().values("myHashKey");
    System.out.println("myHashList資料資訊>>>"+myHashList);
    for (Map.Entry entry : hashValues.entrySet()) {
      System.out.println("myHashValues>>>"+entry.getKey() + " - " + entry.getValue());
    }
    result.put("hashValues",hashValues);

    return result;
  }
}

spring 封裝了 RedisTemplate 物件來進行對redis的各種操作,它支援所有的 redis 原生的 api。在RedisTemplate中提供了幾個常用的介面方法的使用,分別是:

RedisTemplate中定義了對5種資料結構操作

  • redisTemplate.opsForValue();//操作字串
  • redisTemplate.opsForHash();//操作hash
  • redisTemplate.opsForList();//操作list
  • redisTemplate.opsForSet();//操作set
  • redisTemplate.opsForZSet();//操作有序set

注:StringRedisTemplate與 RedisTemplate關係

StringRedisTemplate繼承RedisTemplate,兩者的資料是不共通的;也就是說StringRedisTemplate只能管理StringRedisTemplate裡面的資料,RedisTemplate只能管理RedisTemplate中的資料。SDR預設採用的序列化策略有兩種,一種是String的序列化策略,一種是JDK的序列化策略。StringRedisTemplate預設採用的是String的序列化策略,儲存的key和value都是採用此策略序列化儲存的。RedisTemplate預設採用的是JDK的序列化策略,儲存的key和value都是採用此策略序列化儲存的。

方式2:測試程式碼

@Controller
@RequestMapping("/jedis/")
public class JedisController {

  @Autowired
  private JedisPool jedisPool;

  
  /**
   * @Method: 
   * @Author: 
   * @Description:
   * param: 通過jedis客戶端,往Redis中 存入資料
   * @Return: 
   * @Exception: 
   * @Date: 2020/9/10 10:38
   */
  @RequestMapping("save")
  @ResponseBody
  public Map getSave(String key,String val) {
    Map result=new HashMap();
    boolean executeResult=false;
    Jedis jedis = null;
    try {
      jedis = jedisPool.getResource();
      jedis.set(key,val);
      executeResult=true;
    } catch (Exception e) {
      System.out.println("獲取jedis連結異常"+e);
    }
    result.put("executeResult",executeResult);
    return result;
  }

  /**
   * @Method: 
   * @Author: 
   * @Description:
   * param: 查詢Redis中儲存的資訊
   * @Return: 
   * @Exception: 
   * @Date: 2020/9/10 10:40
   */
  @RequestMapping("queryKeyInfo.do")
  @ResponseBody
  public Map getKey(String key) {
    Map result=new HashMap();
    Jedis jedis = jedisPool.getResource();
    String redisValue=jedis.get(key);
    result.put("key",redisValue);
    return result;
  }
}

通過redis.clients.jedis.JedisPool來管理,即通過池來管理,通過池物件獲取jedis例項,然後通過jedis例項直接操作redis服務,剔除了與業務無關的冗餘程式碼,從工廠類到池的方式變化,就相當於mybatis連線mysql方變化是一樣的,程式碼變得更簡潔,維護也更容易了。Jedis使用apache commons-pool2對Jedis資源池進行管理,所以在定義JedisPool時一個很重要的引數就是資源池GenericObjectPoolConfig

注:使用JedisPool 的方式進行redis操作時候,需要設定redis服務的登入密碼,否則會有相應的錯誤提示。redis.windows.conf 檔案中 通過修改requirepass 資訊來進行redis服務訪問密碼設定,並通過redis-server.exe redis.windows.conf 命令方式進行訪問,否則會報錯:redis.clients.jedis.exceptions.JedisDataException: ERR Client sent AUTH,but no password is set

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。