<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] # 簡介 **SpringBoot導入spring-boot-starter-data-redis時, CacheManager默認使用RedisCache.** 在 Spring Boot 中,默認集成的 Redis 就是 Spring Data Redis,默認底層的連接池使用了 lettuce ,開發者可以自行修改為自己的熟悉的,例如 Jedis。 Spring Data Redis 針對 Redis 提供了非常方便的操作模板 RedisTemplate 。這是 Spring Data 擅長的事情,那么接下來我們就來看看 Spring Boot 中 Spring Data Redis 的具體用法。 Spring Boot 提供了對 Redis 集成的組件包:spring-boot-starter-data-redis,它依賴于 spring-data-redis 和 lettuce。Spring Boot 1.0 默認使?的是 Jedis 客戶端,2.0 替換成了 Lettuce 添加redis依賴 ~~~ <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.2.1.RELEASE</version> </dependency> <!-- 引? commons-pool 2 是因為 Lettuce 需要使? commons-pool 2 創建 Redis 連接池 --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.8.0</version> </dependency> <!-- 在JDK1.8中的時間類,采用了一套了新的API。但是在反序列化中,會出現異常. 此依賴解決 --> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> ~~~ **如果將lettuce客戶端換成jedis客戶端** ~~~xml <!-- Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <!-- jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency> <!--使用redis連接池--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> ~~~ * Lettuce:是?個可伸縮線程安全的 Redis 客戶端,多個線程可以共享同?個 RedisConnection,它利? 優秀 Netty NIO 框架來?效地管理多個連接。 * Spring Data:是 Spring 框架中的?個主要項?,?的是為了簡化構建基于 Spring 框架應?的數據訪問,包括?關系數據庫、Map-Reduce 框架、云數據服務等,另外也包含對關系數據庫的訪問?持。 * Spring Data Redis:是 Spring Data 項?中的?個主要模塊,實現了對 Redis 客戶端 API 的?度封裝, 使對 Redis 的操作更加便捷。 # 配置連接信息 ~~~ ###################Redis################# # Redis數據庫索引(默認為0) spring.redis.database=0 # Redis服務器地址 spring.redis.host=127.0.0.1 # Redis服務器連接端口 spring.redis.port=6379 # Redis服務器連接密碼(默認為空) spring.redis.password=root # 連接池最大連接數(使用負值表示沒有限制) spring.redis.lettuce.pool.max-active=8 # 連接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.lettuce.pool.max-wait=-1 # 連接池中的最大空閑連接 spring.redis.lettuce.pool.max-idle=10 # 連接池中的最小空閑連接 spring.redis.lettuce.pool.min-idle=0 # 連接超時時間(毫秒) spring.redis.lettuce.timeout=1000 ~~~ # redis存儲中文顯示問題 Redis的value存儲中文后,get之后顯示16進制的字符串”\\xe4\\xb8\\xad\\xe5\\x9b\\xbd”,如何解決? ~~~ 127.0.0.1:6379> set China 中國 OK 127.0.0.1:6379> get China "\xe4\xb8\xad\xe5\x9b\xbd" 127.0.0.1:6379> exit ~~~ 解決方法: 啟動redis-cli時,在其后面加上**–raw**即可,漢字即可顯示正常。 **–raw 使用RAW格式回帖(默認時是不是一個TTY標準)** # 配置 ## 序列化 針對StringRedisSerializer,Jackson2JsonRedisSerializer和JdkSerializationRedisSerializer進行測試 | 數據結構 | 序列化類 | 序列化前 | 序列化后 | | --- | --- | --- | --- | | Key/Value | StringRedisSerializer | test\_value | test\_value | | Key/Value | Jackson2JsonRedisSerializer | test\_value | "test\_value" | | Key/Value | JdkSerializationRedisSerializer | test\_value | 亂碼 | | Hash | StringRedisSerializer | 2016-08-18 | 2016-08-18 | | Hash | Jackson2JsonRedisSerializer | 2016-08-18 | "2016-08-18" | | Hash | JdkSerializationRedisSerializer | 2016-08-18 | \\xAC\\xED\\x00\\x05t | **由此可以得到結論:** 1. StringRedisSerializer進行序列化后的值,在Java和Redis中保存的內容時一致的。 2. 用Jackson2JsonRedisSerializer序列化后,在Redis中保存的內容,比Java中多一對逗號。 3. 用JdkSerializationRedisSerializer序列化后,對于Key-Value結構來說,在Redis中不可讀;對于Hash的Value來說,比Java的內容多了一些字符。 作者:小胖學編程 鏈接:https://www.jianshu.com/p/0d4aea41a70c 來源:簡書 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 ~~~ @Resource private RedisTemplate redisTemplate; @Resource private StringRedisTemplate stringRedisTemplate; ~~~ String Data Redis 為我們提供了 RedisTemplate 和 StringRedisTemplate 兩個模版來進行數據操作,其中:StringRedisTemplate 只針對鍵值都是字符串的數據進行操作。 當我們的數據存儲到 Redis 的時候,我們的鍵(key)和 值(value)都是通過 Spring 提供的 Serializer 序列化到數據可中的。 * RedisTemplate 默認使用的是 JdkSerializationRedisSerializer * StringRedisTemplate 默認使用的是 StringRedisSerializer Spring Data JPA 為我們提供了下面的 Serializer * GenericToStringSerializer * Jackson2JsonRedisSerializer * JdkSerializationRedisSerializer * OxmSerializer * StringRedisSerializer Spring Boot 為我們自動配置了 RedisTemplate,而 RedisTemplate 使用的是 JdkSerializationRedisSerializer,這個對我們用 redis 圖形化客戶端很不直觀,因為 JdkSerializationRedisSerializer 使用二進制形式儲存數據,在此我們將自己配置 RedisTemplate 并定義 Serializer ## 配置類 * **@EnableCaching**: 開啟緩存 * **CacheManager**: Spring緩存管理器 * **KeyGenerator**: Redis 緩存鍵生成策略, Spring 默認的DefaultKeyGenerator根據參數列表生成Key,當參數列表的值相同時是一樣的 就會造成獲取到錯誤的緩存數據 ~~~ @EnableCaching注解是spring framework中的注解驅動的緩存管理功能, 當你在配置類(@Configuration)上使用@EnableCaching注解時, 會觸發一個post processor,這會掃描每一個spring bean,查看是否已經存在注解對應的緩存。 如果找到了,就會自動創建一個代理攔截方法調用,使用緩存的bean執行處理。 ~~~ ~~~ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import java.lang.reflect.Method; import java.time.Duration; import java.util.StringJoiner; @Configuration @EnableCaching //開啟緩存 public class RedisConfig extends CachingConfigurerSupport{ /** * @description 緩存key前綴 */ private static final String keyPrefix = "CACHE:"; /** * 在這?可以為 Redis 設置?些全局配置,?如配置主鍵的?產策略 KeyGenerator,如不配置會默認使?參數名作為主鍵。在沒有指定緩存 key 的情況下,key 的默認生成策略 * 注意: 該方法只是聲明了key的生成策略,還未被使用,需在@Cacheable注解中指定keyGenerator * 如: @Cacheable(value = "key", keyGenerator = "keyGenerator") */ @Override @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { //接口提供三個參數,目標類,目標方法,目標參數列表 @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(RedisConfig.keyPrefix); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } @Bean(name="redisTemplate") public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, String> template = new RedisTemplate<>(); RedisSerializer<String> redisSerializer = new StringRedisSerializer(); // 創建序列化類 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); //解決查詢緩存轉換異常的問題 ObjectMapper om = new ObjectMapper(); //注意: 在JDK1.8中的時間類,采用了一套了新的API。但是在反序列化中,會出現異常. ckson-datatype-jsr310依賴解決 om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); om.registerModule(new JavaTimeModule()); //設置可見度 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //啟動默認的類型 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); //序列化類,對象映射設置 jackson2JsonRedisSerializer.setObjectMapper(om); //配置序列化(解決亂碼的問題) template.setConnectionFactory(factory); //key序列化方式 template.setKeySerializer(redisSerializer); //value序列化 template.setValueSerializer(jackson2JsonRedisSerializer); //value hashMap序列化 template.setHashValueSerializer(jackson2JsonRedisSerializer); return template; } //自定義 cacheManager 緩存管理器,全局 @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { RedisSerializer<String> redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); // 配置序列化,redis緩存管理器配置,默認使用 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() //.prefixKeysWith("prefix:") //設置靜態前綴 ; RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith( // key 序列化方式 RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)) // value 序列化方式 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)) // 不緩存null值 //.disableCachingNullValues() //默認緩存過期時間 //.entryTtl(Duration.ofHours(3L)) ; RedisCacheManager cacheManager = RedisCacheManager.builder(factory) .cacheDefaults(redisCacheConfiguration) .build(); return cacheManager; } } ~~~ ## 序列化問題 在JDK1.8中的時間類,采用了一套了新的API。但是在反序列化中,會出現異常。 ~~~ com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of java.time.LocalDate (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) ~~~ 在SpringBoot中的解決方案: * **在MAVEN中加入`ckson-datatype-jsr310`依賴。** ~~~xml <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> ~~~ * **配置Configuration中的ObjectMapper。** ~~~java @Bean public ObjectMapper serializingObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.registerModule(new JavaTimeModule()); return objectMapper; } ~~~ # 測試使用redis * opsForValue:對應 String(字符串) * opsForZSet:對應 ZSet(有序集合) * opsForHash:對應 Hash(哈希) * opsForList:對應 List(列表) * opsForSet:對應 Set(集合) * opsForGeo:對應 GEO(地理位置) ## string ~~~ @Autowired private RedisTemplate redisTemplate; @Test public void test() { redisTemplate.opsForValue().set("neo121", "ityouknow"); Assert.assertEquals("ityouknow", redisTemplate.opsForValue().get("neo121")); } ~~~ ## 對象存儲 對象要有無參構造函數 ~~~ @Autowired private RedisTemplate redisTemplate; @Test public void test() { //對象要有無參構造函數 User user = new User(1, "jdxia"); ValueOperations<String, Object> operations = redisTemplate.opsForValue(); operations.set("com.jdxia", user); User u = (User) operations.get("com.jdxia"); System.out.println(u); } ~~~ ## 設置過期和查詢是否存在 ~~~ //設置過期時間 redisTemplate.expire(key, time, TimeUnit.SECONDS); ~~~ ~~~ // @return 時間(秒) 返回0代表為永久有效;如果該key已經過期,將返回"-2"; redisTemplate.getExpire(key, TimeUnit.SECONDS); ~~~ ~~~ //string設置方式 //這個對象要有無參構造函數 User user = new User(2, "jdxia"); ValueOperations<String, Object> operations = redisTemplate.opsForValue(); //100毫秒 operations.set("com.jdxia", user, 100, TimeUnit.MILLISECONDS); User u = (User) operations.get("com.jdxia"); System.out.println(u); Thread.sleep(1000); Boolean hasKey = redisTemplate.hasKey("com.jdxia"); if (hasKey) { System.out.println("key is exists"); } else { System.out.println("key is not exists"); } ~~~ ## 遞增減 ~~~ redisTemplate.opsForValue().increment(key, delta); redisTemplate.opsForValue().increment(key, -delta); ~~~ ## 刪除數據 ~~~ redisTemplate.delete("deletekey"); ~~~ ## hash ~~~ HashOperations operations = redisTemplate.opsForHash(); operations.put("hash", "hashKey", "hashValue"); String v = (String) operations.get("hash", "hashKey"); System.out.println(v); ~~~ ~~~ //獲取hashKey對應的所有鍵值 redisTemplate.opsForHash().entries(key); ~~~ ~~~ //map 對應多個鍵值, Map<String, Object> map redisTemplate.opsForHash().putAll(key, map); ~~~ ~~~ //可以用這個給hash設置過期時間 redisTemplate.expire(key, time, TimeUnit.SECONDS); ~~~ ~~~ //hash遞增減 redisTemplate.opsForHash().increment(鍵, 項, 增減幾); ~~~ ## list ~~~ ListOperations<String, String> list = redisTemplate.opsForList(); list.leftPush("list","it"); list.leftPush("list","you"); list.leftPush("list","know"); String value=(String)list.leftPop("list"); System.out.println("list value :"+value.toString()); ~~~ ~~~ //將list放入緩存, List<Object> value redisTemplate.opsForList().rightPushAll(key, value); ~~~ ~~~ //key: 鍵, start: 開始, end結束 -1代表所有值 redisTemplate.opsForList().range(key, start, end); ~~~ ~~~ //獲取長度 redisTemplate.opsForList().size(key); ~~~ ~~~ //通過索引 獲取list中的值, index 索引 index>=0時, 0 表頭,1 第二個元素,依次類推;index<0時,-1,表尾,-2倒數第二個元素,依次類推 redisTemplate.opsForList().index(key, index); ~~~ ~~~ //根據索引修改list中的某條數據 redisTemplate.opsForList().set(key, index, value); ~~~ ~~~ //移除n個值為value redisTemplate.opsForList().remove(key, n, value); ~~~ ## set Set 是可以?動排重的 ~~~ String key="set"; //添加 SetOperations<String, String> set = redisTemplate.opsForSet(); set.add(key,"it"); set.add(key,"you"); set.add(key,"you"); set.add(key,"know"); //獲取 Set<String> values = set.members(key); for (String v:values){ System.out.println("set value :"+v); } ~~~ ~~~ //查詢是否存在 redisTemplate.opsForSet().isMember(key, value); ~~~ ~~~ //獲取長度 redisTemplate.opsForSet().size(key); ~~~ ~~~ //刪除,values可以是多個 redisTemplate.opsForSet().remove(key, values); ~~~ Redis 為集合提供了求交集、并集、差集等操作,可以?常?便的使? **差集** ~~~ SetOperations<String, String> set = redisTemplate.opsForSet(); String key1="setMore1"; String key2="setMore2"; set.add(key1,"it"); set.add(key1,"you"); set.add(key1,"you"); set.add(key1,"know"); set.add(key2,"xx"); set.add(key2,"know"); Set<String> diffs=set.difference(key1,key2); for (String v:diffs){ System.out.println("diffs set value :"+v); } ~~~ difference() 函數會把 key 1 中不同于 key 2 的數據對?出來,這個特性適合我 們在?融場景中對賬的時候使?。 **交集** ~~~ SetOperations<String, String> set = redisTemplate.opsForSet(); String key3="setMore3"; String key4="setMore4"; set.add(key3,"it"); set.add(key3,"you"); set.add(key3,"xx"); set.add(key4,"aa"); set.add(key4,"bb"); set.add(key4,"know"); Set<String> unions=set.union(key3,key4); for (String v:unions){ System.out.println("unions value :"+v); } ~~~ unions 會取兩個集合的合集,Set 還有其他很多類似的操作,?常?便我們對集合進? 數據處理 Set 的內部實現是?個 Value 永遠為 null 的 HashMap,實際就是通過計算 Hash 的?式來快速排重, 這也是 Set 能提供判斷?個成員是否在集合內的原因。 ## zset Redis Sorted Set 的使?場景與 Set 類似,區別是 Set 不是?動有序的,? Sorted Set 可以通過?戶額外提供?個優先級(Score)的參數來為成員排序,并且是插?有序,即?動排序 ~~~ String key="zset"; redisTemplate.delete(key); ZSetOperations<String, String> zset = redisTemplate.opsForZSet(); zset.add(key,"it",1); zset.add(key,"you",6); zset.add(key,"know",4); zset.add(key,"neo",3); Set<String> zsets=zset.range(key,0,3); for (String v:zsets){ System.out.println("zset value : " + v ); } Set<String> zsetB=zset.rangeByScore(key,0,3); for (String v:zsetB){ System.out.println("zsetB value :"+v); } ~~~ 通過上?的例?我們發現插?到 Zset 的數據會?動根據 Score 進?排序,根據這個特性我們可以做優先隊 列等各種常?見的場景。另外 Redis 還提供了 rangeByScore 這樣的?個?法,可以只獲取 Score 范圍內排序 后的數據。 Redis Sorted Set 的內部使? HashMap 和跳躍表(SkipList)來保證數據的存儲和有序,HashMap ?放的是成員到 Score 的映射,?跳躍表?存放的是所有的成員,排序依據是 HashMap ?存的 Score, 使?跳躍表的結構可以獲得?較?的查找效率,并且在實現上?較簡單。 ## 查找 ~~~ Set<Serializable> keys = redisTemplate.keys(pattern); ~~~ # 整合session Spring 為 Spring Session 和 Redis 的集成提供了組件:`spring-session-data-redis` ~~~ <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> ~~~ **配置** ~~~ import org.springframework.context.annotation.Configuration; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30) public class SessionConfig {} ~~~ **測試** ~~~ @RequestMapping(value = "/setSession") public Map<String, Object> setSession (HttpServletRequest request){ Map<String, Object> map = new HashMap<>(); request.getSession().setAttribute("message", request.getRequestURL()); map.put("request Url", request.getRequestURL()); return map; } @RequestMapping(value = "/getSession") public Object getSession (HttpServletRequest request){ Map<String, Object> map = new HashMap<>(); map.put("sessionId", request.getSession().getId()); map.put("message", request.getSession().getAttribute("message")); return map; } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看