注:本篇博客SpringBoot版本為2.1.5.RELEASE,SpringBoot1.0版本有些配置不適用
一、SpringBoot 配置Redis
1.1 pom 引入spring-boot-starter-data-redis 包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
1.2 properties配置文件配置redis信息
默認連接本地6379端口的redis服務,一般需要修改配置,例如:
# Redis數據庫索引(默認為0) spring.redis.database=0 # Redis服務器地址 spring.redis.host=127.0.0.1 # Redis服務器連接端口 spring.redis.port=6379 # Redis服務器連接密碼(默認為空) spring.redis.password= # 連接池最大連接數(使用負值表示沒有限制) spring.redis.jedis.pool.max-active=20 # 連接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.jedis.pool.max-wait=-1 # 連接池中的最大空閑連接 spring.redis.jedis.pool.max-idle=10 # 連接池中的最小空閑連接 spring.redis.jedis.pool.min-idle=0 # 連接超時時間(毫秒) spring.redis.timeout=1000
二、RedisTemplate<K,V>類的配置
Spring 封裝了RedisTemplate<K,V>對象來操作redis。
2.1 Spring對RedisTemplate<K,V>類的默認配置(了解即可)
Spring在 org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration類下配置的兩個RedisTemplate的Bean。
(1) RedisTemplate<Object, Object>
這個Bean使用JdkSerializationRedisSerializer進行序列化,即key, value需要實現Serializable接口,redis數據格式比較難懂,例如
(2) StringRedisTemplate,即RedisTemplate<String, String>
key和value都是String。當需要存儲實體類時,需要先轉為String,再存入Redis。一般轉為Json格式的字符串,所以使用StringRedisTemplate,需要手動將實體類轉為Json格式。如
ValueOperations<String, String> valueTemplate = stringTemplate.opsForValue(); Gson gson = new Gson(); valueTemplate.set("StringKey1", "hello spring boot redis, String Redis"); String value = valueTemplate.get("StringKey1"); System.out.println(value); valueTemplate.set("StringKey2", gson.toJson(new Person("theName", 11))); Person person = gson.fromJson(valueTemplate.get("StringKey2"), Person.class); System.out.println(person);
2.2 配置一個RedisTemplate<String,Object>的Bean
Spring配置的兩個RedisTemplate都不太方便使用,所以可以配置一個RedisTemplate<String,Object> 的Bean,key使用String即可(包括Redis Hash 的key),value存取Redis時默認使用Json格式轉換。如下
@Bean(name = "template") public RedisTemplate<String, Object> template(RedisConnectionFactory factory) { // 創建RedisTemplate<String, Object>對象 RedisTemplate<String, Object> template = new RedisTemplate<>(); // 配置連接工廠 template.setConnectionFactory(factory); // 定義Jackson2JsonRedisSerializer序列化對象 Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修飾符范圍,ANY是都有包括private和public om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,比如String,Integer等會報異常 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); StringRedisSerializer stringSerial = new StringRedisSerializer(); // redis key 序列化方式使用stringSerial template.setKeySerializer(stringSerial); // redis value 序列化方式使用jackson template.setValueSerializer(jacksonSeial); // redis hash key 序列化方式使用stringSerial template.setHashKeySerializer(stringSerial); // redis hash value 序列化方式使用jackson template.setHashValueSerializer(jacksonSeial); template.afterPropertiesSet(); return template; }
所以可以這樣使用
@Autowired
private RedisTemplate<String, Object> template;
public void test002() {
ValueOperations<String, Object> redisString = template.opsForValue();
// SET key value: 設置指定 key 的值
redisString.set("strKey1", "hello spring boot redis");
// GET key: 獲取指定 key 的值
String value = (String) redisString.get("strKey1");
System.out.println(value);
redisString.set("strKey2", new User("ID10086", "theName", 11));
User user = (User) redisString.get("strKey2");
System.out.println(user);
}
2.3 配置Redis operations 的Bean
RedisTemplate<K,V>類以下方法,返回值分別對應操作Redis的String、List、Set、Hash等,可以將這些operations 注入到Spring中,方便使用
/** * redis string */ @Bean public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForValue(); } /** * redis hash */ @Bean public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForHash(); } /** * redis list */ @Bean public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForList(); } /** * redis set */ @Bean public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForSet(); } /** * redis zset */ @Bean public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForZSet(); }
三、RedisTemplate類的API使用
RedisTemplate是Spring封裝的類,它的API基本上對應了Redis的命令,下面列舉了一小部分的使用,更多的請查看Javadoc。
@Autowired private HashOperations<String, String, Object> redisHash;// Redis Hash @Test public void test003() { Map<String, Object> map = new HashMap<>(); map.put("id", "10010"); map.put("name", "redis_name"); map.put("amount", 12.34D); map.put("age", 11); redisHash.putAll("hashKey", map); // HGET key field 獲取存儲在哈希表中指定字段的值 String name = (String) redisHash.get("hashKey", "name"); System.out.println(name); // HGET key field Double amount = (Double) redisHash.get("hashKey", "amount"); System.out.println(amount); // HGETALL key 獲取在哈希表中指定 key 的所有字段和值 Map<String, Object> map2 = redisHash.entries("hashKey"); System.out.println(map2); // HKEYS key 獲取在哈希表中指定 key 的所有字段 Set<String> keySet = redisHash.keys("hashKey"); System.out.println(keySet); // HVALS key 獲取在哈希表中指定 key 的所有值 List<Object> valueList = redisHash.values("hashKey"); System.out.println(valueList); }
四、使用Redis緩存數據庫數據
Redis有很多使用場景,一個demo就是緩存數據庫的數據。Redis作為一個內存數據庫,存取數據的速度比傳統的數據庫快得多。使用Redis緩存數據庫數據,可以減輕系統對數據庫的訪問壓力,及加快查詢效率等好處。下面講解如何使用 SpringBoot + Redis來緩存數據庫數據(這里數據庫使用MySql)。
4.1 配置Redis作為Spring的緩存管理
Spring支持多種緩存技術:RedisCacheManager、EhCacheCacheManager、GuavaCacheManager等,使用之前需要配置一個CacheManager的Bean。配置好之后使用三個注解來緩存數據:@Cacheable,@CachePut 和 @CacheEvict。這三個注解可以加Service層或Dao層的類名上或方法上(建議加在Service層的方法上),加上類上表示所有方法支持該注解的緩存;三注解需要指定Key,以返回值作為value操作緩存服務。所以,如果加在Dao層,當新增1行數據時,返回數字1,會將1緩存到Redis,而不是緩存新增的數據。
RedisCacheManager的配置如下:
/** * <p>SpringBoot配置redis作為默認緩存工具</p> * <p>SpringBoot 2.0 以上版本的配置</p> */ @Bean public CacheManager cacheManager(RedisTemplate<String, Object> template) { RedisCacheConfiguration defaultCacheConfiguration = RedisCacheConfiguration .defaultCacheConfig() // 設置key為String .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer())) // 設置value 為自動轉Json的Object .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer())) // 不緩存null .disableCachingNullValues() // 緩存數據保存1小時 .entryTtl(Duration.ofHours(1)); RedisCacheManager redisCacheManager = RedisCacheManagerBuilder // Redis 連接工廠 .fromConnectionFactory(template.getConnectionFactory()) // 緩存配置 .cacheDefaults(defaultCacheConfiguration) // 配置同步修改或刪除 put/evict .transactionAware() .build(); return redisCacheManager; }
4.2 @Cacheabl、@CachePut、@CacheEvict的使用
package com.github.redis; import com.github.mybatis.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import java.util.List; /** * 指定默認緩存區 * 緩存區:key的前綴,與指定的key構成redis的key,如 user::10001 */ @CacheConfig(cacheNames = "user") @Service public class RedisCacheUserService { @Autowired private UserDao dao; /** * @Cacheable 緩存有數據時,從緩存獲取;沒有數據時,執行方法,並將返回值保存到緩存中 * @Cacheable 一般在查詢中使用 * 1) cacheNames 指定緩存區,沒有配置使用@CacheConfig指定的緩存區 * 2) key 指定緩存區的key * 3) 注解的值使用SpEL表達式 * eq == * lt < * le <= * gt > * ge >= */ @Cacheable(cacheNames = "user", key = "#id") public User selectUserById(String id) { return dao.selectUserById(id); } @Cacheable(key="'list'") public List<User> selectUser() { return dao.selectUser(); } /** * condition 滿足條件緩存數據 */ @Cacheable(key = "#id", condition = "#number ge 20") // >= 20 public User selectUserByIdWithCondition(String id, int number) { return dao.selectUserById(id); } /** * unless 滿足條件時否決緩存數據 */ @Cacheable(key = "#id", unless = "#number lt 20") // < 20 public User selectUserByIdWithUnless(String id, int number) { return dao.selectUserById(id); } /**
* @CachePut 一定會執行方法,並將返回值保存到緩存中 * @CachePut 一般在新增和修改中使用 */ @CachePut(key = "#user.id") public User insertUser(User user) { dao.insertUser(user); return user; } @CachePut(key = "#user.id", condition = "#user.age ge 20") public User insertUserWithCondition(User user) { dao.insertUser(user); return user; } @CachePut(key = "#user.id") public User updateUser(User user) { dao.updateUser(user); return user; } /** * 根據key刪除緩存區中的數據 */ @CacheEvict(key = "#id") public void deleteUserById(String id) { dao.deleteUserById(id); } /** * allEntries = true :刪除整個緩存區的所有值,此時指定的key無效 * beforeInvocation = true :默認false,表示調用方法之后刪除緩存數據;true時,在調用之前刪除緩存數據(如方法出現異常) */ @CacheEvict(key = "#id", allEntries = true) public void deleteUserByIdAndCleanCache(String id) { dao.deleteUserById(id); } }
五、項目地址
項目github地址,里面的測試類均有對上面涉及的內容進行測試。喜歡的幫忙點個Star
https://github.com/caizhaokai/spring-boot-demo