redis是什麼相信你們都有具體的瞭解,不瞭解的同窗最好先去官方網站查閱學習。java
咱們以前講到的緩存系統,默認使用的是ConcurrentMapCacheManager==ConcurrentMapCache,默認開啓的是SimpleCacheConfiguration配置,咱們以前分析過,他還支持其餘的不少緩存配置,包括咱們要講到的redis。mysql
經過將redis集成到咱們的緩存系統,咱們就能夠輕鬆的經過reids的客戶端查詢對應的緩存信息,實現了緩存信息的可視化。web
印象筆記 —— redis是一個比傳統數據庫更輕量,但卻擁有強大功能的「數據庫」,通常在應用中充當緩存組件,例如做爲數據庫和應用程序上層的中間件、提供session會話信息保存等。redis
docker pull redis
docker run -d -p 6379:6379 --name redis redis
docker ps
輸出spring
439e18fd2ea6 rabbitmq:3-management "docker-entrypoint..." 5 days ago Up 5 days 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp, 15671/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp rabbit 3d9ee1d941b0 redis "docker-entrypoint..." 5 days ago Up 5 days 0.0.0.0:6379->6379/tcp redis 402fbb3778ad docker.elastic.co/elasticsearch/elasticsearch:6.5.3 "/usr/local/bin/do..." 5 days ago Up 5 days 0.0.0.0:9200->9200/tcp, 0.0.0.0:9300->9300/tcp loving_carson e3ef44911869 mariadb "docker-entrypoint..." 5 days ago Up 5 days 0.0.0.0:3306->3306/tcp mysql 59f9c80d269b tomcat "catalina.sh run" 5 days ago Up 5 days 0.0.0.0:8080->8080/tcp goofy_swartz
以前我已經裝好了redis,咱們能夠看到redis已經在咱們端口6379上映射好了,接下來就可使用redis客戶端鏈接並查看咱們本身的redis了。sql
Connect to Redis Server
按鈕(若是您的版本和個人差很少的話,應該在右下方往右數的第二個按鈕,有一個綠色的+
),按照咱們的redis環境對其進行配置,若是成功的話,雙擊生成的redis服務,就能夠看到出現16個數據倉庫,說明您整個過程已經成功了。通常都是以下的配置Name : 隨意寫 Host : 你的Redis服務器id Port: 6379 Auth: 無需填寫
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
spring: redis: host: 10.21.1.47 port: 6379
port默認6379,若是是默認端口的話咱們也能夠不予指定。docker
/* * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.data.redis; import java.net.UnknownHostException; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Redis support. * * @author Dave Syer * @author Andy Wilkinson * @author Christian Dupuis * @author Christoph Strobl * @author Phillip Webb * @author Eddú Meléndez * @author Stephane Nicoll * @author Marco Aust * @author Mark Paluch */ @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate( RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
能夠看出,他爲咱們提供了兩個組件類,一個是RedisTemplate(k-v都是對象),一個是StringRedisTemplate(k-v都是字符串)。因爲咱們常用字符串操做,因此redis配置類中爲提供了stringRedisTemplate這個組件。shell
咱們能夠直接在應用中直接注入就可使用了。數據庫
redis支持的五大數據類型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、ZSet(有序集合),咱們均可以使用springboot提供的組件類進行操做。express
經過
redisTemplate.opsXXX.redis提供的Command
來操做相應的數據。例如redisTemplate.opsForHash.
package com.zhaoyi.aweb; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class AwebApplicationTests { @Autowired StringRedisTemplate stringRedisTemplate; @Autowired RedisTemplate redisTemplate; @Test public void test01() { stringRedisTemplate.opsForValue().append("name", "a"); stringRedisTemplate.opsForValue().append("name","kuya"); System.out.println(stringRedisTemplate.opsForValue().get("name")); } @Test public void contextLoads() { } }
運行test01測試方法後,咱們的redis存儲庫中存儲了一個String類型的name數據,其值爲akuya,其餘的操做你們均可以一一逐個測試,固然不一樣的數據類型設置和獲取由些許差別。
接下來咱們使用RedisTemplate類型的template來測試對象的保存。
@Autowired RedisTemplate redisTemplate; @Test public void test02() { Integer id = 1; String key = "user_" + id; User user = userService.getUser(id); redisTemplate.opsForValue().set(key, user); System.out.println(redisTemplate.opsForValue().get(key)); }
咱們查詢id=2的用戶信息,並以user_{id}
爲key的方式存儲一個對象user的信息,運行測試用例test02咱們會發現報錯:
... java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.zhaoyi.aweb.bean.User] ...
提示咱們須要提供的應該是一個可序列化的有效載荷(patload)類型,所以,咱們須要將User標誌爲可序列化的對象類型。
public class User implements Serializable { private static final long serialVersionUID = 4125096758372084309L;
咱們再運行以後,查看redis客戶端的存儲信息發現
key=\xAC\xED\x00\x05t\x00\x06user_1 value = \xAC\xED\x00\x05sr\x00\x19com.zhaoyi.aweb.bean.User\xC7\xD7\xAC\x00\x0F\xDB\x0A\x97\x02\x00\x04L\x00\x0CdepartmentIdt\x00\x13Ljava/lang/Integer;L\x00\x02idq\x00~\x00\x01L\x00\x09loginNamet\x00\x12Ljava/lang/String;L\x00\x08userNameq\x00~\x00\x02xpsr\x00\x11java.lang.Integer\x12\xE2\xA0\xA4\xF7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xAC\x95\x1D\x0B\x94\xE0\x8B\x02\x00\x00xp\x00\x00\x00\x01q\x00~\x00\x06t\x00\x05akuyat\x00\x09\xE9\x98\xBF\xE5\xBA\x93\xE5\xA8\x85
也就是說,保存對象時,都是以jdk序列化機制,不論是key仍是value都是序列化的字符串了。
一般,咱們仍是習慣本身轉化爲json方式來存儲:
咱們先查看默認狀況下用的是什麼序列化器:
if (defaultSerializer == null) { defaultSerializer = new JdkSerializationRedisSerializer( classLoader != null ? classLoader : this.getClass().getClassLoader()); }
也就是JdkSerializationRedisSerializer
,接下來,咱們修改成本身的序列化器。
package com.zhaoyi.aweb.config; import com.zhaoyi.aweb.bean.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import java.net.UnknownHostException; @Configuration public class MyConfig { @Bean public RedisTemplate<String, User> redisTemplateUser(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<String, User> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); // 設置默認的序列化器 Jackson2JsonRedisSerializer<User> userJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<User>(User.class); template.setDefaultSerializer(userJackson2JsonRedisSerializer); return template; } }
而後,咱們使用該template來進行redis的存儲操做
@Autowired RedisTemplate<String, User> redisTemplate; @Test public void test02() { Integer id = 1; String key = "user_" + id; User user = userService.getUser(id); redisTemplate.opsForValue().set(key, user); //System.out.println(redisTemplate.opsForValue().get(key)); }
查看咱們的redis客戶端,就能夠看到不論是key仍是value都是易讀的的形式了:
key = "user_1" value = { "id": 1, "loginName": "akuya", "userName": "阿庫婭", "departmentId": 1 }
咱們引入redis的starter以後,咱們的容器中的緩存管理器變成了RedisCacheManager,他的做用是建立了RedisCache
來做爲緩存組件,RedisCachle經過咱們配置的redis來進行緩存數據。
前面咱們使用查詢user的時候,會發現redis生成了一個名叫
user
命名空間,緩存了咱們查詢的用戶信息。
默認建立的RedisCacheManager使用的是RedisTemplate<Object,Object>,他默認使用的序列化器仍是咱們默認的JDK序列化機制。要改變這種行爲,咱們一樣須要建立本身的自定義CacheManager,注意2.0和1.x版本仍是有很大的區別,請當心版本帶來的問題。
但在尋找其區別的時候,我發現一個問題,那就是咱們應用中不可能沒有一個類就寫一個template,所以,咱們須要寫一個通用的redis底層存儲配置,也就是說遵循:以String
類型的數據做爲key,以json字符串做爲結果進行存儲,所以,編寫了以下的配置器,若是嫌麻煩的同窗能夠直接複製過去使用,兼容任何的類與底層緩存:
package com.zhaoyi.aweb.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.*; import java.net.UnknownHostException; @Configuration public class JoyRedisConfig { /** * 配置RedisTemplate<String,Object> * @param redisConnectionFactory * @return * @throws UnknownHostException */ @Bean public RedisTemplate<String,Object> redisTemplateUser(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<String, Object> template = new RedisTemplate(); template.setConnectionFactory(redisConnectionFactory); // 設置序列化器 template.setDefaultSerializer(valueSerializer()); return template; } @Bean public RedisCacheManager redisCacheManagerUser(RedisConnectionFactory redisConnectionFactory){ // 這裏能夠配置超時時間等 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration // Default { using the following: // key expiration === eternal // cache null values === yes // prefix cache keys===yes // default prefix===the actual cache name // key serializer === org.springframework.data.redis.serializer.StringRedisSerializer // value serializer === org.springframework.data.redis.serializer.JdkSerializationRedisSerializer // conversion service === DefaultFormattingConversionService with #registerDefaultConverters(ConverterRegistry) default .defaultCacheConfig() // Define the {@link SerializationPair} used for de-/serializing cache keys. .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) // Define the {@link SerializationPair} used for de-/serializing cache values. .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) // Disable caching .disableCachingNullValues(); return RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(redisCacheConfiguration) .transactionAware() .build(); } // key序列化器 private RedisSerializer<String> keySerializer() { return new StringRedisSerializer(); } // Value序列化器 private RedisSerializer<Object> valueSerializer() { return new GenericJackson2JsonRedisSerializer(); } }
咱們能夠看到經過配置
@Cacheable(value = "user", key = "#id")
生成的緩存key的樣子爲user::1
,也就是說cacheName指定的值,生成了user::這樣的前綴,在redis中以名稱空間的形式存在;另外,若是咱們以@Cacheable(value = {"user","saber"}, key = "#id")
,這樣存儲的話,結果會在user和saber兩個名稱空間中,存儲兩份結果,即user::1
和saber::1
。
注意這是2.x版本,簡化配置。基本知足須要,若是您有詳細的配置,例如超時時間、針對具體的容器進行配置,能夠在
redisCacheConfiguration
配置。
還記得
@CacheManager
註解嗎,他所指定的就是咱們如今定義的這些CacheManager了。
若是你配置了多個緩存管理器,別忘了爲默認的緩存管理器添加一個
@Primary
註解。