Redis数据库读写教程


Redis 与传统的关系型数据库不同,其数据存储介质是内存而非硬盘,众所周知内存的读取速度远大于硬盘,因此对于 Redis 在应用中通常扮演者缓存的角色。

其中较为常见的应用场景即将系统的热点数据提前加载至 Redis 中,当应用程序需要访问时直接读取缓存即可,从而提供程序效率。在之前的文章中也介绍了如何在 Spring Boot 工程中通过注解方式实现数据缓存。

这篇文章将介绍如何自定义进行 Redis 数据库基本读写操作,这里的工程我基于之前的项目进行改造,没有看过之前文章的小伙伴可以先简单过一遍:Redis缓存配置

1. 依赖引入

首先需要在项目中引入 Redis 相关 Maven 依赖。

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

2. Bean注入

我们直接在之前的配置类 RedisConfig 中新增如下代码:

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
    template.setConnectionFactory(factory);

    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    // key 采用 String 的序列化方式
    template.setKeySerializer(stringRedisSerializer);
    // key 的哈希值采用 String 的序列化方式
    template.setHashKeySerializer(stringRedisSerializer);
    // value 序列化方式采用 jackson
    template.setValueSerializer(jackson2JsonRedisSerializer);
    // value 的哈希值序列化方式采用 jackson
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();

    return template;
}

3. 基本操作

为了后续的读存更加方便,在这里对 RedisTemplate 的接口二次封装为我们自己的工具类。

新建 RedisUtils 类,内容如下:

@Service
public class RedisUtils {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 判断 key 是否存在
     *
     * @param key 键
     */
    public Boolean hasKey(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key can not be null!");
        }

        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 key 过期时间
     *
     * @param key 键
     * @return 时间, 0代表为永久有效
     */
    public Long getExpire(String key, TimeUnit timeUnit) {
        if (key == null) {
            throw new IllegalArgumentException("key can not be null!");
        }

        Long expireTime = -1L;
        if (hasKey(key)) {
            expireTime = redisTemplate.getExpire(key, timeUnit);
        }
        return expireTime;
    }

    /**
     * 设置 key 过期时间
     *
     * @param key 键
     * @return 时间, 0代表为永久有效
     */
    public Boolean setExpire(String key, long time, TimeUnit timeUnit) {
        Boolean flag;
        try {
            if (hasKey(key)) {
                flag = redisTemplate.expire(key, time, timeUnit);
            } else {
                throw new RuntimeException("The key doesn't exist.");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return flag;
    }

    /**
     * 缓存放入, 默认无限期
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 缓存放入并设置过期时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间, 0 将设置无限期
     */
    public void setWithTime(String key, Object value, long time, TimeUnit timeUnit) {
        try {
            if (time <= 0) {
                set(key, value);
            } else {
                redisTemplate.opsForValue().set(key, value, time, timeUnit);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key can not be null!");
        }

        Object object = null;
        if (hasKey(key)) {
            object = redisTemplate.opsForValue().get(key);
        }
        return object;
    }

    /**
     * 删除数据
     *
     * @param key 键
     */
    public Boolean delete(String key) {
        if (key == null) {
            throw new IllegalArgumentException("key can not be null!");
        }

        Boolean flag = false;
        if (hasKey(key)) {
            flag = redisTemplate.delete(key);
        }
        return flag;
    }

    /**
     * 批量删除缓存
     *
     * @param keys 可以传一个值 或多个
     */
    public void batchDelete(Collection keys) {
        if (!CollectionUtils.isEmpty(keys)) {
            redisTemplate.delete(keys);
        } else {
            throw new IllegalArgumentException("keys can not be null!");
        }
    }
}

4. 读取示例

这里以之前的 Spring 数据缓存为例,在不通过注解的方式实现数据的缓存存储。

下面我们就可以通过上面封装的方法对 Redis 数据库进行操作了,首先确定一下缓存的业务逻辑:

当业务在读取数据之前,应该先根据指定 KeyRedis 中进行读取,

  • 存在,直接返回缓存数据。
  • 不存在,从数据库中查询数据返回,并将结果存入 Redis 缓存中。

其实只是我们将之前注解帮我们做的事自己用代码实现了而已。

通过封装的 RedisService 调用之前封装好的 get()set() 方法,具体示例如下:

public class RedisController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisService redisService;

    @GetMapping("/list")
    public List<User> get(@Param("accountID") String accountID){
        List<User> userList ;
        // 先从 Redis 数据库读取数据
        userList = (List<User>) redisService.get("users:list");
        // 如果未查询到数据再从 MySQL 中读取
        if(userList == null) {
            userList = userService.list();
            // 将查出来的数据存入 Redis 数据库
            redisService.set("users:list", userList, 5);
        }
        return userList;
    }
}

5. 写入示例

通过封装的 RedisService 调用之前封装好的 get()set() 方法,具体示例如下:

public class RedisController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisService redisService;

    @PostMapping("/add")
    public int update(@RequestBody User user) throws Exception {
        User userResult = userService.get(user.getAccountID());
        if (userResult == null) {
            // 根据 Key 删除缓存
            redisService.delete("users:list");
            return userService.add(user);
        } else {
            return -1;
        }
    }
}

文章作者: 烽火戏诸诸诸侯
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 烽火戏诸诸诸侯 !
  目录