SpringBoot2.3.4整合Redis實現緩存

文章主要內容

1、SpringCache 介紹html

2、SpringCache 註解java

3、註解方式實現Redis緩存(Windows版Redis)mysql

4、RedisUtils工具類原生方式實現Redis緩存(Windows版Redis)redis

1、SpringCache介紹

官方文檔地址:https://docs.spring.io/spring...spring

image

在Spring Boot中,數據的緩存管理存儲依賴於Spring框架中cache相關的org.springframework.cache.Cache和org.springframework.cache.CacheManager緩存管理器接口。sql

若是程序中沒有定義類型爲CacheManager的Bean組件或者是名爲cacheResolver的CacheResolver緩存解析器,Spring Boot將嘗試選擇並啓用如下緩存組件(按照指定的順序):數據庫

(1)Genericapache

(2)JCache (JSR-107)(EhCache 三、Hazelcast、Infinispan等)編程

(3)EhCache 2.xjson

(4)Hazelcast

(5)Infinispan

(6)Couchbase

(7)Redis

(8)Caffeine

(9)Simple

上面按照Spring Boot緩存組件的加載順序,列舉了支持的9種緩存組件,在項目中添加某個緩存管理組件(例如Redis)後,Spring Boot項目會選擇並啓用對應的緩存管理器。若是項目中同時添加了多個緩存組件,且沒有指定緩存管理器或者緩存解析器(CacheManager或者cacheResolver),那麼Spring Boot會按照上述順序在添加的多個緩存中優先啓用指定的緩存組件進行緩存管理。

Spring Boot默認緩存管理中,沒有添加任何緩存管理組件能實現緩存管理。這是由於開啓緩存管理後,Spring Boot會按照上述列表順序查找有效的緩存組件進行緩存管理,若是沒有任何緩存組件,會默認使用最後一個Simple緩存組件進行管理。Simple緩存組件是Spring Boot默認的緩存管理組件,它默認使用內存中的ConcurrentMap進行緩存存儲,因此在沒有添加任何第三方緩存組件的狀況下,能夠實現內存中的緩存管理,可是咱們不推薦使用這種緩存管理方式

當在Spring Boot默認緩存管理的基礎上引入Redis緩存組件,即在pom.xml文件中添加Spring Data Redis依賴啓動器後,SpringBoot會使用RedisCacheConfigratioin當作生效的自動配置類進行緩存相關的自動裝配,容器中使用的緩存管理器是RedisCacheManager, 這個緩存管理器建立的Cache爲 RedisCache, 進而操控redis進行數據的緩存

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

核心思想:當咱們調用一個方法時會把該方法的參數和返回結果最爲一個鍵值對存放在緩存中,等下次利用一樣的參數來調用該方法時將不會再執行,而是直接從緩存中獲取結果進行返回。

理解:springboot 的緩存機制是經過切面編程 aop來實現的

2、SpringCache 註解

Spring Cache 提供了 @Cacheable 、@CachePut 、@CacheEvict 、@Caching 等註解,在方法上使用。

基於註解方式SpringCache引入Redis作緩存,須要先了解@EnableCaching、@CacheConfig、@Cacheable、@CachePut、@CacheEvict、@Caching相關注解的使用

一、@EnableCaching

開啓緩存功能,通常放在啓動類上或者自定義的RedisConfig配置類上。

二、@CacheConfig

當咱們須要緩存的地方愈來愈多,可使用@CacheConfig(cacheNames = "cacheName")註解在 class 之上來統一指定value的值,統一管理keys,這時可省略value,若是你在你的方法依舊寫上了value,那麼依然以方法的value值爲準。

示例:

@Service
@CacheConfig(cacheNames = "categories")
public class CategoryServiceImpl implements CategoryService{
 
    ......
}

image

三、@Cacheable

根據方法對其返回結果進行緩存,下次請求時,若是緩存存在,則直接讀取緩存數據返回;若是緩存不存在,則執行方法,並把返回的結果存入緩存中。通常用在查詢方法上。 查看源碼,屬性值以下:

屬性/方法名 解釋
value 緩存名,指定了緩存存放在哪塊命名空間(必須)
cacheNames 與value差很少,二選一便可
key 緩存的key,可使用SPEL標籤自定義緩存的key
keyGenerator key的生存器。key/keyGenerator二選一使用
cacheManager 指定緩存管理器
cacheResolver 指定獲取解析器
condition 條件符合則緩存
unless 條件符合則不緩存
sync 是否使用異步模式,默認爲false

四、@CachePut

使用該註解標誌的方法,每次都會執行,並將結果存入指定的緩存中。其餘方法能夠直接從響應的緩存中讀取緩存數據,而不須要再去查詢數據庫。通常用在新增方法上。 查看源碼,屬性值同上@Cacheable差很少

五、@CacheEvict

使用該註解標誌的方法,會清空指定的緩存。通常用在更新或者刪除方法上

查看源碼,屬性值與@Cacheable差很少,獨有的兩個屬性以下:

屬性/方法名 解釋
allEntries 是否清空全部緩存,默認爲false。若是指定爲true,則方法調用後將當即清空全部的緩存
beforeInvocation 是否在方法執行前就清空全部緩存,默認爲false。若是指定爲true,則方法執行前就會清空全部的緩存

六、@Caching

該註解能夠實現同一個方法上同時使用多種註解。可從其源碼看出:

public @interface Caching {
    
    Cacheable[] cacheable() default {};
    CachePut[] put() default {};
    CacheEvict[] evict() default {};
}

3、註解方式實現Redis緩存(Windows版Redis)

一、數據庫及數據環境準備

CREATE DATABASE `redistest`CHARACTER SET utf8 COLLATE utf8_general_ci; 
USE `redistest`; 

CREATE TABLE `user`(
  id INT(11)NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255)DEFAULT NULL,
  `password` VARCHAR(255)DEFAULT NULL,
  PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES(1,'張三',"123456789");
INSERT INTO `user` VALUES(2,'李四',"asdfghj");
INSERT INTO `user` VALUES(3,'王麻子',"kjfdskjf");
INSERT INTO `user` VALUES(4,'小明',"hellorworld");
INSERT INTO `user` VALUES(5,'李華',"redis");

二、構建一個SpringBoot項目,勾選相應的模塊,添加Pom依賴

image

添加其餘的Pom依賴

<!-- mybatis 持久層-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

三、application.properties配置文件

# ============數據庫============
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/redistest?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=admin

# ============mybatis============
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.type-aliases-package=com.cqy.pojo
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# ============redis============
# 默認是使用0號數據庫,這裏咱們使用1號,筆者如今0號有其餘數據- -
spring.redis.database=1 
spring.redis.host=localhost
spring.redis.port=6379
# 默認密碼爲空
spring.redis.password=
# 鏈接池最大鏈接數
spring.redis.lettuce.pool.max-active=8
# 鏈接池最大阻塞等待時間
spring.redis.lettuce.pool.max-wait=-1ms
# 鏈接池中的最大空閒鏈接
spring.redis.lettuce.pool.max-idle=8
# 鏈接池中的最小空閒鏈接
spring.redis.lettuce.pool.min-idle=0

四、pojo實體類

@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    
    private int id;
    private String name;
    private String password;
}

五、dao層的Mapper接口

@Repository
@Mapper
public interface UserMapper {

    /**
     * 增長
     * @param user
     * @return
     */
    public int addUser(User user);

    /**
     * 刪除
     * @param id
     * @return
     */
    public int deleteUser(@Param("id") int id);

    /**
     * 修改
     * @param user
     * @return
     */
    public int updateUser(User user);

    /**
     * 查詢獲取全部User對象
     * @return
     */
    public List<User> selectUser();

    /**
     * 根據id查詢獲取某個User對象
     * @param id
     * @return
     */
    public User selectUserById(@Param("id") int id);
    
    /**
     * 查詢一共有幾條數據
     * @return
     */
    public int countUser();
}

六、Mapper接口對應的Mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.cqy.dao.UserMapper">

    <insert id="addUser" parameterType="user">
        insert into `user` (`name`,password) values (#{name},#{password})
    </insert>

    <delete id="deleteUser" parameterType="_int">
        delete from `user` where id =#{id}
    </delete>

    <update id="updateUser" parameterType="user">
        update `user` set `name`=#{name},password=#{password} where id=#{id}
    </update>

    <select id="selectUser" resultType="user">
        select * from `user`
    </select>

    <select id="selectUserById" parameterType="_int" resultType="user">
        select * from `user` where id =#{id}
    </select>
    
    <select id="countUser" resultType="_int">
        select count(*) from `user`
    </select>

</mapper>

七、UserService和UserServiceImpl

UserService接口同UserMapper的內容同樣,略。

UserServiceImpl:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    public int addUser(User user) {
        return userMapper.addUser(user);
    }

    @Override
    public int deleteUser(int id) {
        return userMapper.deleteUser(id);
    }

    @Override
    public int updateUser(User user) {
        return userMapper.updateUser(user);
    }

    @Override
    public List<User> selectUser() {
        return userMapper.selectUser();
    }

    @Override
    public User selectUserById(int id) {
        return userMapper.selectUserById(id);
    }
    
    @Override
    public int countUser() {
        return userMapper.countUser();
    }
}

八、單元測試簡單的CRUD是否成功

@SpringBootTest
class RedisTestSpringbootApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void test() {
        List<User> users = userService.selectUser();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

發現報錯:

image

解決:添加Pom依賴

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.8.0</version>
</dependency>

九、構建RedisConfig配置類

一般咱們都使用Json序列化後存入Redis,而SpringBoot1.x和SpringBoot2.x版本在自定義CacheManager有很大的區別,須要自行研讀源碼。

在此簡單說明,但不作源碼詳細分析。

在SpringBoot1.x中,RedisCacheManager是可使用RedisTemplate做爲參數注入的

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

但在SpringBoot2.x中,有很大的不一樣,RedisCacheManager構造器以下,已經沒法再使用RedisTemplate進行構造

image

官方文檔中:

image

說明如今配置RedisCacheManager須要一個RedisCacheConfiguration來做爲配置對象,經過RedisCacheConfiguration這個對象來指定對應的序列化策略

SpringBoot2.x後自定義CacheManager有多種方式,筆者此處直接給出本身所用的一種。其餘的構建方法,可自行百度,有不少方法。

@Configuration
@SuppressWarnings("all")
@EnableCaching
public class RedisConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解決查詢緩存轉換異常的問題
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解決亂碼的問題)
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofDays(1))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }
}

RedisConfig的json序列化配置文章參考:

一、https://blog.csdn.net/weixin_...

二、https://blog.csdn.net/qq_4153...

十、在UserServiceImpl使用註解進行Redis緩存

注意:須要先在RedisConfig加上@EnableCaching,表示開啓緩存功能

@Service
@CacheConfig(cacheNames = "user")
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;

    @Override
    @CachePut(key = "'user-id-'+ #user.id")
    public int addUser(User user) {
        System.out.println("寫入緩存");
        return userMapper.addUser(user);
    }

    @Override
    @CacheEvict(key = "'user-id-'+#p0")//根據key清除緩存,通常該註解標註在修改和刪除方法上
    public int deleteUser(int id) {
        return userMapper.deleteUser(id);
    }

    @Override
    @CacheEvict(key = "'user-id-'+#user.id")//根據key清除緩存,通常該註解標註在修改和刪除方法上
    public int updateUser(User user) {
        System.out.println("更新數據並清除以前的緩存");
        return userMapper.updateUser(user);
    }

    @Override
    @Cacheable(cacheNames = "userList") // 標誌讀取緩存操做,若是緩存不存在,則調用目標方法,並將結果放入緩存
    public List<User> selectUser() {
        System.out.println("緩存不存在,執行方法");
        return userMapper.selectUser();
    }

    @Override
    @Cacheable(key = "'user-id-'+#p0")
    public User selectUserById(int id) {
        System.out.println("緩存不存在,執行方法");
        return userMapper.selectUserById(id);
    }
}

其中#p0是指的第一個參數,#p1是第二個參數,以此類推。

十一、單元測試查看緩存

啓動redis-server和RedisDesktopManager

運行單元測試,管理工具查看緩存

@SpringBootTest
class RedisTestSpringbootApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void select() {
        List<User> users = userService.selectUser();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    void selectById() {
        User users = userService.selectUserById(3);
        System.out.println(users);
    }

    @Test
    void add() {
        userService.addUser(new User(6,"小紅","56458848"));
    }

    @Test
    void update() {
        userService.updateUser(new User(6,"紙飛機","1111111"));
    }

    @Test
    void delete() {
        userService.deleteUser(6);
    }
}

image

4、RedisUtils工具類原生方式實現Redis緩存(Windows版Redis)

使用SpringCache的註解方式實現Redis緩存,底層邏輯原理其實就是Redis的set、get命令操做key-value,將操做返回的結果存到Redis中,下次執行一樣操做的時候,進行判斷邏輯看Redis中是否有值,存在的話就直接從Redis中拿value,實現緩存效果。

所以,咱們可直接利用RedisUtils的方式,進行邏輯的set、get實現緩存。這種方式不少時候序列化和key的設置都相對更靈活一些,但相對也較複雜一些。

一、數據庫及數據環境準備

二、構建一個SpringBoot項目,勾選相應的模塊,添加Pom依賴

三、application.properties配置文件

四、pojo實體類

五、dao層的Mapper接口

六、Mapper接口對應的Mapper.xml文件

七、UserService和UserServiceImpl

八、單元測試簡單的CRUD是否成功

以上步驟都同第三部分同樣,再也不贅述。

九、構建RedisConfig配置類

RedisConfig中自定義redisTemplate的bean

@Configuration
@SuppressWarnings("all")
public class RedisConfig {


    @Bean(name="myredisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        //Json序列化設置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //經過ObjectMapper轉義json
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        //String類型的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        //key採用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key也採用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value的序列化方式採用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        //hash的value序列化方式採用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

十、RedisUtils封裝工具類準備

@Component
public class RedisUtils {

    @Autowired
    @Qualifier("myredisTemplate")
    private RedisTemplate<String,Object> redisTemplate;

    // =============================common============================
    /**
     * 指定緩存失效時間
     * @param key 鍵
     * @param time 時間(秒)
     * @return
     */
    public boolean expire(String key,long time){
        try {
            if (time > 0){
                redisTemplate.expire(key,time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 根據key獲取過時時間
     * @param key 鍵  不能爲null
     * @return 時間(秒) 返回0表明爲永久有效
     */
    public long getExpire(String key){
        return redisTemplate.getExpire(key,TimeUnit.SECONDS);
    }




    /**
     * 判斷key是否存在
     * @param key  鍵
     * @return  true的話存在,false不存在
     */
    public boolean hasKey(String key){
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 刪除緩存
     * @param key  能夠傳一個key或多個key
     */
    @SuppressWarnings("unchecked")
    public void del(String... key){
        if (key!=null && key.length>0){
            if (key.length==1){
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }
    }


    // ============================String=============================


    /**
     * 普通緩存獲取
     * @param key 鍵
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }


    /**
     * 普通緩存放入
     * @param key   鍵
     * @param value 值
     * @return true成功 false失敗
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 普通緩存放入並設置時間
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒) time要大於0 若是time小於等於0 將設置無限期
     * @return true成功 false 失敗
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 遞增
     * @param key   鍵
     * @param delta 要增長几(大於0)
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞增因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }


    /**
     * 遞減
     * @param key   鍵
     * @param delta 要減小几(小於0)
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("遞減因子必須大於0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }


    // ================================HashMap=================================


    /**
     * HashGet
     * @param key  鍵 不能爲null
     * @param item 項 不能爲null
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }


    /**
     * 獲取hashKey對應的全部鍵值
     * @param key 鍵
     * @return 對應的多個鍵值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }


    /**
     * HashSet
     * @param key 鍵
     * @param map 對應多個鍵值
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * HashSet 並設置時間
     * @param key  鍵
     * @param map  對應多個鍵值
     * @param time 時間(秒)
     * @return true成功 false失敗
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 向一張hash表中放入數據,若是不存在將建立
     *
     * @param key   鍵
     * @param item  項
     * @param value 值
     * @return true 成功 false失敗
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 向一張hash表中放入數據,若是不存在將建立
     *
     * @param key   鍵
     * @param item  項
     * @param value 值
     * @param time  時間(秒) 注意:若是已存在的hash表有時間,這裏將會替換原有的時間
     * @return true 成功 false失敗
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 刪除hash表中的值
     *
     * @param key  鍵 不能爲null
     * @param item 項 可使多個 不能爲null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }


    /**
     * 判斷hash表中是否有該項的值
     *
     * @param key  鍵 不能爲null
     * @param item 項 不能爲null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }


    /**
     * hash遞增 若是不存在,就會建立一個 並把新增後的值返回
     *
     * @param key  鍵
     * @param item 項
     * @param by   要增長几(大於0)
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }


    /**
     * hash遞減
     *
     * @param key  鍵
     * @param item 項
     * @param by   要減小記(小於0)
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }


    // ============================set=============================


    /**
     * 根據key獲取Set中的全部值
     * @param key 鍵
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 根據value從一個set中查詢,是否存在
     *
     * @param key   鍵
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 將數據放入set緩存
     *
     * @param key    鍵
     * @param values 值 能夠是多個
     * @return 成功個數
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 將set數據放入緩存
     *
     * @param key    鍵
     * @param time   時間(秒)
     * @param values 值 能夠是多個
     * @return 成功個數
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0)
                expire(key, time);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 獲取set緩存的長度
     *
     * @param key 鍵
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 移除值爲value的
     *
     * @param key    鍵
     * @param values 值 能夠是多個
     * @return 移除的個數
     */


    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    // ===============================list=================================


    /**
     * 獲取list緩存的內容
     *
     * @param key   鍵
     * @param start 開始
     * @param end   結束 0 到 -1表明全部值
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 獲取list緩存的長度
     *
     * @param key 鍵
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 經過索引 獲取list中的值
     *
     * @param key   鍵
     * @param index 索引 index>=0時, 0 表頭,1 第二個元素,依次類推;index<0時,-1,表尾,-2倒數第二個元素,依次類推
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 將list放入緩存
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒)
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 將list放入緩存
     *
     * @param key   鍵
     * @param value 值
     * @param time  時間(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0)
                expire(key, time);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根據索引修改list中的某條數據
     *
     * @param key   鍵
     * @param index 索引
     * @param value 值
     * @return
     */

    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N個值爲value
     *
     * @param key   鍵
     * @param count 移除多少個
     * @param value 值
     * @return 移除的個數
     */

    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

十一、在UserServiceImpl中進行redis緩存邏輯bianxie

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;
    @Autowired
    RedisUtils redisUtils;

    public static final String CACHE_KEY_USER="user:";

    @Override
    public int addUser(User user) {
        //先直接修改數據庫中的數據,方法執行後再更新緩存
        int i = userMapper.addUser(user);
        redisUtils.set(CACHE_KEY_USER+user.getId(),user);
        return i;
    }

    @Override
    public int deleteUser(int id) {
        //方法執行後刪除redis中相應的緩存
        int i = userMapper.deleteUser(id);
        redisUtils.del(CACHE_KEY_USER+id);
        return i;
    }

    @Override
    public int updateUser(User user) {
        //先直接修改數據庫中的數據
        int i = userMapper.updateUser(user);
        //方法執行後更新redis中相應的緩存
        int id = user.getId();
        redisUtils.set(CACHE_KEY_USER+user.getId(),user);
        return i;
    }

    @Override
    public List<User> selectUser() {
        int i = countUser();
        Object object = redisUtils.get(CACHE_KEY_USER + "number:"+i);
        //判斷redis中是否存在緩存的key-value
        if (null != object){
            //有,直接返回
            return (List<User>) object;
        }
        //沒有,去數據庫中查詢,並將查詢的結果存到redis中
        List<User> users = userMapper.selectUser();
        redisUtils.set(CACHE_KEY_USER + "number:"+i,users);
        return users;
    }

    @Override
    public User selectUserById(int id) {
        Object object = redisUtils.get(CACHE_KEY_USER + id);
        //判斷redis中是否存在緩存的key-value
        if (null != object){
            //有,直接返回
            return (User) object;
        }
        //沒有,去數據庫中查詢,並將查詢的結果存到redis中
        User user = userMapper.selectUserById(id);
        redisUtils.set(CACHE_KEY_USER + id,user);
        return user;
    }

    @Override
    public int countUser() {
        return userMapper.countUser();
    }
}

十二、單元測試查看緩存

@SpringBootTest
class RedisTest01SpringbootApplicationTests {

    @Autowired
    UserService userService;

    @Test
    void selectById() {
        User user = userService.selectUserById(3);
        System.out.println(user);
    }

    @Test
    void select() {
        List<User> users = userService.selectUser();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    void add() {
        userService.addUser(new User(6,"紙飛機","1998dsadsasd"));
    }

    @Test
    void delete() {
        userService.deleteUser(6);
    }

    @Test
    void update() {
        userService.updateUser(new User(6,"紙飛機666","helloredis"));
    }
}

以上只是特別簡單的redis操做,其他的設置key的過時時間等,直接使用redisUtils進行設置便可。

5、總結

redis緩存本質仍舊是操做redis其中的五大數據類型,須要熟練掌握,而且能知曉用在何處,怎麼用。

參考:

一、https://segmentfault.com/a/11... 整合Redis緩存實現 目標字節的禿禿
二、https://juejin.im/post/684490... Spring Boot 2.X(七):Spring Cache 使用 朝霧輕寒
三、https://juejin.im/post/684490... 優雅的緩存解決方案--SpringCache和Redis集成(SpringBoot) 米奇羅


謝謝您看完這篇技術文章

若是能對您有所幫助

那將是一件很美好的事情

保持好奇心的終身學習也是極棒的事

願世界簡單又多彩

轉載請註明出處

​ ——紙飛機

相關文章
相關標籤/搜索