1. 程式人生 > >SpringBoot整合Redis(單機版)

SpringBoot整合Redis(單機版)

一:環境搭建.

      1.1 SpringBoot的環境是 1.5.10.RELEASE.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

    1.2 已配置好開啟Server服務的Redis一臺.

   1.3 檢視所有的key,發現是空的.(keys * 通配)

   1.4 IDEA下推薦一款外掛,Redis的客戶端工具.Iedis.

   下載連結:Iedis 提取碼(9sjd).安裝方式就是載入硬盤裡面的外掛,然後重新啟動IDEA即可.

效果如下.

這裡在命令列新增一個String型別的key看一下效果吧.

 

二:Redis的配置.

     2.1 由於前文我們原始碼分析了Data-Redis,對配置比較瞭解, 配置RestTemplate.這裡使用RedisTemplate.StringRedisTemplate繼承了RedisTemplate。

   2.2 application.properties新增連線資訊.

#配置Redis
spring.redis.database=0
spring.redis.host=Redis IP
spring.redis.port=6379
spring.redis.password=123456
#最大連線數
spring.redis.pool.max-active=8
#最大阻塞時間,負值表示沒有限制
spring.redis.pool.max-wait=-1
#最小空閒連線數
spring.redis.pool.min-idle=0
#最大空閒連線數
spring.redis.pool.max-idle=8
#連線超時時間(毫秒)
spring.redis.timeout=10000

 2.3 Java註解配置RedisTemplate.

       RedisCacheConfig(注意導包的正確性)配置泛型型別<Object, Object>

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
/**
 * author: 
 * date: 
 * time: 
 * description: 配置Redis快取
 */
@Configuration
public class RedisCacheConfig {
   @Value("${spring.redis.database}")
   private int database;
   @Value("${spring.redis.host}")
   private String host;
   @Value("${spring.redis.port}")
   private int port;
   @Value("${spring.redis.password}")
   private String password;
   @Value("${spring.redis.pool.max-active}")
   private int maxActive;
   @Value("${spring.redis.pool.max-idle}")
   private int maxIdle;
   @Value("${spring.redis.pool.min-idle}")
   private int minIdle;
   @Value("${spring.redis.pool.max-wait}")
   private int maxWait;

   /** 配置JedisConnectionFactory*/
   @Bean
   public JedisConnectionFactory jedisConnectionFactory(){
       JedisConnectionFactory factory=new JedisConnectionFactory();
       factory.setDatabase(database);
       factory.setHostName(host);
       factory.setPassword(password);
       factory.setPort(port);
       JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
       jedisPoolConfig.setMaxTotal(maxActive);
       jedisPoolConfig.setMaxIdle(maxIdle);
       jedisPoolConfig.setMinIdle(minIdle);
       jedisPoolConfig.setMaxWaitMillis(maxWait);
       factory.setPoolConfig(jedisPoolConfig);
       return factory;
   }
   /** SpringBoot自定義配置RedisTemplate*/
   @Bean
   @SuppressWarnings({"rawtypes", "unchecked"})
   public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
       RedisTemplate<Object, Object> template=new RedisTemplate<>();
       template.setConnectionFactory(redisConnectionFactory);
       // 使用Jackson2JsonRedisSerialize 替換預設序列化
       Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
       ObjectMapper mapper=new ObjectMapper();
       mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
       mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
       jackson2JsonRedisSerializer.setObjectMapper(mapper);
       // 設定value的序列化規則和 key的序列化規則
       template.setValueSerializer(jackson2JsonRedisSerializer);
       template.setKeySerializer(new StringRedisSerializer());
       template.setHashKeySerializer(new StringRedisSerializer());
       template.afterPropertiesSet();
       return  template;
   }
}

2.4                        方式一:使用Jedis提供的Java客戶端API方法操作Redis.

     RedisController如下.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
 * author: 
 * date: 
 * time: 
 * description:Redis的五種資料型別操作
 */
@RestController
@RequestMapping("/redis")
public class RedisController {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @RequestMapping("/value")
    public Object redis(){
        redisTemplate.opsForValue().set("name", "tomcat");
        ValueOperations<Object, Object> value=redisTemplate.opsForValue();
        Object name=value.get("name").toString();
        // 輸出value
        System.out.println("獲取的值:"+name);
        return name;
    }

    @RequestMapping("/list")
    public List<Object> list(){
        ListOperations<Object, Object> list=redisTemplate.opsForList();
        list.leftPush("s-list", "Chinese");
        list.leftPush("s-list", "Math");
        list.leftPush("s-list", "English");
        // 輸出list
        System.out.println(list.range("s-list",0,2));
        List<Object> resultList=list.range("s-list",0,2);
        return resultList;
    }

    @RequestMapping("/set")
    public Set<Object> set(){
        SetOperations<Object, Object> set = redisTemplate.opsForSet();
        set.add("p-set", "ps");
        set.add("p-set", "27");
        set.add("p-set", "180cm");
        // 輸出set
        System.out.println(set.members("p-set"));
        Set<Object> resultSet=set.members("p-set");
        return resultSet;
    }

   @RequestMapping("/zset")
   public Set<Object> zset(){
       ZSetOperations<Object, Object> zset=redisTemplate.opsForZSet();
       zset.add("z-set", "ps", 0);
       zset.add("z-set", "27", 1);
       zset.add("z-set", "180cm",2);
       // 輸出zset
       System.out.println(zset.range("z-set",0, 2));
       Set<Object> resultZSet=zset.range("z-set",0, 2);
       return resultZSet;
   }

   @RequestMapping("/hash")
    public Map<Object,Object> hash(){
        HashOperations<Object, Object, Object> hash=redisTemplate.opsForHash();
        Map<Object, Object> map=new HashMap();
        map.put("name", "lucy");
        map.put("age", 22);
        map.put("address", "重慶市");
        hash.putAll("map",map);
        // 輸出map
        System.out.println(hash.entries("map"));
        Map<Object, Object> resultMap=hash.entries("map");
        return resultMap;
   }
}

 瀏覽器測試如下:

  String型別的.

② List型別的.

③ Set型別的.

④:ZSet型別的.

⑤:Hash型別.

IDEA的Redis外掛檢視一下吧.

刪除所有的key.del key(後面跟多個key,返回成功刪除的個數).

                                               方式二:宣告式註解操作

啟動類新增@EnableCaching,開啟宣告式註解.

首先來看一下Spring對快取的支援.

Spring定義了CacheManager和Cahce介面來統一不同的快取技術,例如,單體版的快取服務,分散式的快取服務等,良好的可擴充套件性

CacheManager是Spring框架提供的各種快取技術抽象介面.

Cahce介面包含快取的各種操作(增加,刪除,獲取快取).

CacheManager介面位置如下.

CacheManager.使用Spring快取必不可少的.

getCache():獲取指定的名稱的快取物件.

getCacheNames():返回Cache的集合.

SpringBoot為我們自動配置了多個CacheManager.不同我們自己配置CacheManagerle 那我們可以就 嘿嘿了.

SpringBoot預設是以spring.cache為字首的屬性配置快取的.SpringBoot會自動根據spring.cahce的型別判斷使用的快取型別.

宣告式快取註解.

①:Cacheable

在方法執行前Spring先檢視快取中是否有資料,如果有資料,則直接返回快取中的資料,如果沒有資料,呼叫方法並將方法返回值放進快取中.

②:CachePut

無論怎樣,直接將方法的返回值放進快取中.

③:CacheEvict

將一條或多條資料從快取中刪除.

④:Caching

可以通過@Caching註解將多個註解策略放在一個方法上.

配置RedisCacheManager.

@Bean
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate){
     RedisCacheManager cacheManager=new RedisCacheManager(redisTemplate);
     return cacheManager;
}

Service層使用快取.

快取物件集合中,快取是以key-value形式儲存的。當不指定快取的key時,SpringBoot會使用SimpleKeyGenerator生成key。

由於key如果自己不指定預設就是方法的方法的所有引數組合.由於配置了Remplate的Key的規則是StringRedisSerializer.不能是Integer的入口引數,否則報型別不匹配的錯誤的.這裡的key是使用的SpringEL獲取的id值.如果不是能夠獲取的值就報如下錯誤的.

例如這樣的寫法 key="user-#id";

// key為id,value是方法的返回值
@Cacheable(value="UserCache",key="#id")
public User getUserById(String id) {
     System.out.println("開始查詢");
        System.out.println("為id="+id+"的資料做了快取!");
        Integer userId=Integer.valueOf(id);
        User user= userMapper.getUserById(Integer.valueOf(id));
        System.out.println("結束查詢");
        return user;
    }

Controller層

@RestController
@RequestMapping("/annot/redis")
public class AnnotRedisController {
    
    @Autowired
    private UserService userService;

    @RequestMapping("/search/{id}")
    public User getUser(@PathVariable("id") String id){
        User user=null;
        if(id!=null){
            user=userService.getUserById(id);
        }
        return user;
 }

瀏覽器訪問測試[email protected]

這個時候清空控制檯,多次請求觀察.發現控制檯沒有輸出Service的開始查詢執行的方法,是走了Redis快取的.

這個時候查詢一下快取吧.

使用@CacheEvict從快取XXX中刪除key為id的資料.

Service層

 @Override
 @CacheEvict(value="UserCache")
    public int delete(String id) {
        System.out.println("刪除了id="+id+"的資料快取!");
        return userMapper.delete(Integer.valueOf(id));
 }

Controller層

    @RequestMapping("/delete/{id}")
    public String deleteUser(@PathVariable("id") String id){
        if(id!=null){
            userService.delete(id);
            return "Delete Success";
        }
        return "Delete Fail";
    }

瀏覽器測試一下吧.

檢視刪除效果.

@CachePut:是快取新增或者是更新後的資料到快取.測試一下吧.所以和@Cacheable的屬性要一樣的.快取屬性名和key要一致.

更新的是value值.

由於使用id的這種方式極容易出現重複的.衝突的.(使用是的引數名拼成的快取key),如果兩個方法的引數是一樣的,但是裡面的執行邏輯不同,這樣我們執行第二個方法不就命中第一個方法的快取了嗎.

解決的方法就是我們自己制定key ,或者是實現一個KeyGenerator,在註解中指定KeyGenerator.在註解中指定KeyGenerator即可.但是如果這樣的情況很多,每一個都要指定key、KeyGenerator很麻煩。

Spring框架提供:繼承CachingConfigurerSupport並重寫keyGenerator()。

  RedisCacheConfig繼承CacingConfigurerSupport.

    @Bean
    public KeyGenerator userKeyGenerator() {
        return new KeyGenerator(){
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder builder=new StringBuilder();
                builder.append(target).append("-").append(method).append("-");
                for(Object obj:params){
        builder.append("-").append(obj);
             }
                return builder.toString();
             }
        };
                }

這樣的快取key就是包名+方法名+引數名了.只有三者都相同參會衝突的.

首先是訪問id=4的使用者,將資料由資料庫查詢出來存放至快取裡面.

至此完成了基於API方法呼叫和註解的兩種方式整合了Redis.