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
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。