Spring框架接入單機(jī)Redis兩種實(shí)現(xiàn)方式解析
1、Redis的簡(jiǎn)單介紹
1)Redis 是一個(gè)開源(BSD許可)的,內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)系統(tǒng),它可以用作數(shù)據(jù)庫(kù)、緩存和消息中間件。 它支持多種類型的數(shù)據(jù)結(jié)構(gòu),如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與范圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 這些數(shù)據(jù)類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。Redis 內(nèi)置了 復(fù)制(replication),LUA腳本(Lua scripting), LRU驅(qū)動(dòng)事件(LRU eviction),事務(wù)(transactions) 和不同級(jí)別的 磁盤持久化(persistence), 并通過 Redis哨兵(Sentinel)和自動(dòng) 分區(qū)(Cluster)提供高可用性(high availability)。Redis 是完全開源免費(fèi)的,遵守BSD協(xié)議,是一個(gè)高性能的key-value數(shù)據(jù)庫(kù)。
2)Redis的內(nèi)存管理機(jī)制:
在Redis中,并不是所有的數(shù)據(jù)都一直存儲(chǔ)在內(nèi)存中的。當(dāng)物理內(nèi)存用完時(shí),Redis可以將一些很久沒用到的value交換到磁盤。Redis只會(huì)緩存所有的key的信息,如果Redis發(fā)現(xiàn)內(nèi)存的使用量超過了某一個(gè)閥值,將觸發(fā)swap的操作,Redis根據(jù)“swappability = age*log(size_in_memory)”計(jì)算出哪些key對(duì)應(yīng)的value需要swap到磁盤。然后再將這些key對(duì)應(yīng)的value持久化到磁盤中,同時(shí)在內(nèi)存中清除。這種特性使得Redis可以保持超過其機(jī)器本身內(nèi)存大小的數(shù)據(jù)。
3)Redis性能和集群管理:
Redis雖然支持?jǐn)?shù)據(jù)的持久化,但是全內(nèi)存畢竟才是其高性能的本質(zhì)。作為基于內(nèi)存的存儲(chǔ)系統(tǒng)來說,機(jī)器物理內(nèi)存的大小就是系統(tǒng)能夠容納的最大數(shù)據(jù)量。如果需要處理的數(shù)據(jù)量超過了單臺(tái)機(jī)器的物理內(nèi)存大小,就需要構(gòu)建分布式集群來擴(kuò)展存儲(chǔ)能力。Redis更偏向于在服務(wù)器端構(gòu)建分布式存儲(chǔ)。
4)Redis 同其他 key - value 緩存數(shù)據(jù)庫(kù)比較具有以下
- Redis支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保存在磁盤中,重啟的時(shí)候可以再次加載進(jìn)行使用。
- Redis不僅僅支持簡(jiǎn)單的key-value類型的數(shù)據(jù),同時(shí)還提供list,set,zset,hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。
- Redis支持?jǐn)?shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。
5)Redis優(yōu)勢(shì)
- .性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
- .豐富的數(shù)據(jù)類型 – Redis支持二進(jìn)制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作。
- .原子 – Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行。單個(gè)操作是原子性的。多個(gè)操作也支持事務(wù),即原子性,通過MULTI和EXEC指令包起來。
- .豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。
- .Redis運(yùn)行在內(nèi)存中但是可以持久化到磁盤,所以在對(duì)不同數(shù)據(jù)集進(jìn)行高速讀寫時(shí)需要權(quán)衡內(nèi)存,因?yàn)閿?shù)據(jù)量不能大于硬件內(nèi)存。在內(nèi)存數(shù)據(jù)庫(kù)方面的另一個(gè)優(yōu)點(diǎn)是,相比在磁盤上相同的復(fù)雜的數(shù)據(jù)結(jié)構(gòu),在內(nèi)存中操作起來非常簡(jiǎn)單,這樣Redis可以做很多內(nèi)部復(fù)雜性很強(qiáng)的事情。同時(shí),在磁盤格式方面他們是緊湊的以追加的方式產(chǎn)生的,因?yàn)樗麄儾⒉恍枰M(jìn)行隨機(jī)訪問。
2、spring框架中接入redis的兩種方式:
步驟1:引入相關(guān)依賴
<!--使用jedis 需要引入 commons-pool 的依賴,否則Jedis會(huì)實(shí)例化失敗--> <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中 如果存儲(chǔ)的是Map<String,Object>需要導(dǎo)入jackson相關(guān)的包,存儲(chǔ)的時(shí)候使用json序列化器存儲(chǔ)。如果不導(dǎo)入jackson的包會(huì)報(bào)錯(cuò)。 --> <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相關(guān)屬性文件:redis.properties
#訪問地址 redis.host=127.0.0.1 #訪問端口 redis.port=6379 #注意,如果沒有password,此處不設(shè)置值,但這一項(xiàng)要保留 redis.password=@redisLearn #最大空閑數(shù),數(shù)據(jù)庫(kù)連接的最大空閑時(shí)間。超過空閑時(shí)間,數(shù)據(jù)庫(kù)連接將被標(biāo)記為不可用,然后被釋放。設(shè)為0表示無(wú)限制。 redis.maxIdle=300 #連接池的最大數(shù)據(jù)庫(kù)連接數(shù)。設(shè)為0表示無(wú)限制 redis.maxActive=600 #最大建立連接等待時(shí)間。如果超過此時(shí)間將接到異常。設(shè)為-1表示無(wú)限制。 redis.maxWait=1000 #在borrow一個(gè)jedis實(shí)例時(shí),是否提前進(jìn)行alidate操作;如果為true,則得到的jedis實(shí)例均是可用的; redis.testOnBorrow=true #客戶端連接超時(shí)時(shí)間 redis.timeout=30000 #可用數(shù)據(jù)庫(kù)數(shù) redis.database = 0
步驟3:Spring中引入Redis配置、及調(diào)用實(shí)例(方式1和方式2選擇其中一種進(jìn)行配置)
方式1:通過spring-data-redis工具實(shí)現(xiàn)對(duì)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 "> <!-- 連接池基本參數(shù)配置,類似數(shù)據(jù)庫(kù)連接池 --> <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> <!-- 連接池配置,類似數(shù)據(jù)庫(kù)連接池 --> <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總結(jié).pass}"></property> --> <property name="poolConfig" ref="poolConfig"></property> </bean> <!--redis操作模版,使用該對(duì)象可以操作redis --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" > <property name="connectionFactory" ref="jedisConnectionFactory" /> <!--如果不配置Serializer,那么存儲(chǔ)的時(shí)候缺省使用String,如果用User類型存儲(chǔ),那么會(huì)提示錯(cuò)誤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> <!--開啟事務(wù) --> <property name="enableTransactionSupport" value="true"></property> </bean > </beans>
方式2:通過jedis客戶端工具實(shí)現(xiàn)對(duì)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 "> <!-- 連接池基本參數(shù)配置,類似數(shù)據(jù)庫(kù)連接池 --> <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中進(jìn)行 進(jìn)行 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:接入測(cè)試
方式1:測(cè)試代碼
@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", 0, -1); for (String s : myListKeyValues) { System.out.println("myListKey數(shù)據(jù)元素>>>"+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"); redisTemplate.opsForSet().add("mySetKey", "setValue3"); Set<String> setValues = redisTemplate.opsForSet().members("mySetKey"); for (String s : setValues) { System.out.println("mySetKey數(shù)據(jù)元素>>>"+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數(shù)據(jù)信息>>>"+myHashList); for (Map.Entry entry : hashValues.entrySet()) { System.out.println("myHashValues>>>"+entry.getKey() + " - " + entry.getValue()); } result.put("hashValues",hashValues); return result; } }
spring 封裝了 RedisTemplate 對(duì)象來進(jìn)行對(duì)redis的各種操作,它支持所有的 redis 原生的 api。在RedisTemplate中提供了幾個(gè)常用的接口方法的使用,分別是:
RedisTemplate中定義了對(duì)5種數(shù)據(jù)結(jié)構(gòu)操作
- redisTemplate.opsForValue();//操作字符串
- redisTemplate.opsForHash();//操作hash
- redisTemplate.opsForList();//操作list
- redisTemplate.opsForSet();//操作set
- redisTemplate.opsForZSet();//操作有序set
注:StringRedisTemplate與 RedisTemplate關(guān)系
StringRedisTemplate繼承RedisTemplate,兩者的數(shù)據(jù)是不共通的;也就是說StringRedisTemplate只能管理StringRedisTemplate里面的數(shù)據(jù),RedisTemplate只能管理RedisTemplate中的數(shù)據(jù)。SDR默認(rèn)采用的序列化策略有兩種,一種是String的序列化策略,一種是JDK的序列化策略。StringRedisTemplate默認(rèn)采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。RedisTemplate默認(rèn)采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
方式2:測(cè)試代碼
@Controller @RequestMapping("/jedis/") public class JedisController { @Autowired private JedisPool jedisPool; /** * @Method: * @Author: * @Description: * param: 通過jedis客戶端,往Redis中 存入數(shù)據(jù) * @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中存儲(chǔ)的信息 * @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來管理,即通過池來管理,通過池對(duì)象獲取jedis實(shí)例,然后通過jedis實(shí)例直接操作redis服務(wù),剔除了與業(yè)務(wù)無(wú)關(guān)的冗余代碼,從工廠類到池的方式變化,就相當(dāng)于mybatis連接mysql方變化是一樣的,代碼變得更簡(jiǎn)潔,維護(hù)也更容易了。Jedis使用apache commons-pool2對(duì)Jedis資源池進(jìn)行管理,所以在定義JedisPool時(shí)一個(gè)很重要的參數(shù)就是資源池GenericObjectPoolConfig
注:使用JedisPool 的方式進(jìn)行redis操作時(shí)候,需要設(shè)置redis服務(wù)的登錄密碼,否則會(huì)有相應(yīng)的錯(cuò)誤提示。redis.windows.conf 文件中 通過修改requirepass 信息來進(jìn)行redis服務(wù)訪問密碼設(shè)置,并通過redis-server.exe redis.windows.conf 命令方式進(jìn)行訪問,否則會(huì)報(bào)錯(cuò):redis.clients.jedis.exceptions.JedisDataException: ERR Client sent AUTH, but no password is set
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- SpringBoot中使用redis做分布式鎖的方法
- 多個(gè)SpringBoot項(xiàng)目采用redis實(shí)現(xiàn)Session共享功能
- SpringBoot中使用Redis的完整實(shí)例
- Spring Cache整合Redis實(shí)現(xiàn)方法詳解
- spring boot+redis 監(jiān)聽過期Key的操作方法
- SpringBoot2.3整合redis緩存自定義序列化的實(shí)現(xiàn)
- 詳解SpringBoot Redis自適應(yīng)配置(Cluster Standalone Sentinel)
- SpringBoot整合Redis正確的實(shí)現(xiàn)分布式鎖的示例代碼
- SpringBoot使用Redis實(shí)現(xiàn)分布式鎖
相關(guān)文章
數(shù)據(jù)庫(kù)連接池c3p0配置_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了數(shù)據(jù)庫(kù)連接池c3p0配置的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08一文詳解SpringMVC中的@RequestMapping注解
@RequestMapping是一個(gè)用于映射HTTP請(qǐng)求到處理方法的注解,在Spring框架中使用,它可以用于控制器類和處理方法上,用來指定處理不同URL路徑的請(qǐng)求,并定義請(qǐng)求的方法等,本文小編將給大家詳細(xì)的介紹一下SpringMVC中的@RequestMapping注解,需要的朋友可以參考下2023-08-08使用Filter攔截器如何實(shí)現(xiàn)請(qǐng)求跨域轉(zhuǎn)發(fā)
這篇文章主要介紹了使用Filter攔截器如何實(shí)現(xiàn)請(qǐng)求跨域轉(zhuǎn)發(fā),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08解決SpringBoot運(yùn)行報(bào)錯(cuò):找不到或無(wú)法加載主類的問題
這篇文章主要介紹了解決SpringBoot運(yùn)行報(bào)錯(cuò):找不到或無(wú)法加載主類的問題,具有很好的參考價(jià)值,對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下2023-09-09使用mybatis的typeHandler對(duì)clob進(jìn)行流讀寫方式
這篇文章主要介紹了使用mybatis的typeHandler對(duì)clob進(jìn)行流讀寫方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01使用LambdaQueryWrapper動(dòng)態(tài)加過濾條件?動(dòng)態(tài)Lambda
這篇文章主要介紹了使用LambdaQueryWrapper動(dòng)態(tài)加過濾條件?動(dòng)態(tài)Lambda,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01如何解決java:錯(cuò)誤:無(wú)效的源發(fā)行版:16
這篇文章主要介紹了如何解決java:錯(cuò)誤: 無(wú)效的源發(fā)行版:16問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04基于SpringCloudGateway實(shí)現(xiàn)微服務(wù)網(wǎng)關(guān)的方式
Spring?Cloud?Gateway是Spring?官方基于Spring?5.0,Spring?Boot?2.0和Project?Reactor?等技術(shù)開發(fā)的網(wǎng)關(guān),旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單而有效的統(tǒng)一的API路由管理方式,對(duì)SpringCloudGateway實(shí)現(xiàn)微服務(wù)網(wǎng)關(guān)相關(guān)知識(shí)感興趣的朋友一起看看吧2021-12-12