博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redis使用进阶
阅读量:6424 次
发布时间:2019-06-23

本文共 9614 字,大约阅读时间需要 32 分钟。

Redis之使用教程(Java版)

关键词

  • Jedis: redis java客户端实现.
  • Lettuce: redis java客户端实现, 基于netty.
  • spring-data-redis: Spring针对redis的封装, 配置简单, 提供了与Redis存储交互的抽象封装, 十分优雅, 也极具扩展性. 可集成Jedis、Lettuce等redis客户端. springboot2.0后官方默认集成的客户端从Jedis改为Lettuce.

前言

本文将针对使用Java集成Redis进行讲解, JedisLettuce的使用仅作简单描述, springredis集成及使用将作为主要讲解内容.

Jedis

引入依赖:

redis.clients
jedis
2.9.3
复制代码

Jedis是对redis命令的封装, 使用上基本与redis-cli无异, 操作string的使用示例如下:

/** jedis pool */private static final JedisPool POOL = new JedisPool(new JedisPoolConfig(), "test-redis-server", 6379);// test Binary-safe strings with Jedistry (Jedis jedis = POOL.getResource()){     {   // SET mykey myvalue        String result = jedis.set("mykey", "myvalue");        LOGGER.info("cmd: SET mykey myvalue, result: {}", result);    }    {   // GET mykey        String result = jedis.get("mykey");        LOGGER.info("cmd: GET mykey, result: {}", result);    }    {   // KEYS my*        Set
keys = jedis.keys("my*"); LOGGER.info("cmd: KEYS my*, result: {}", JsonUtils.writeValueAsString(keys, true)); } { // EXISTS mykey Boolean result = jedis.exists("mykey"); LOGGER.info("cmd: EXISTS mykey, result: {}", result); } { // DEL mykey Long result = jedis.del("mykey"); LOGGER.info("cmd: DEL mykey, result: {}", result); } { // GET mykey String result = jedis.get("mykey"); LOGGER.info("cmd: GET mykey, result: {}", result); }}复制代码
  • JedisPool: Jedis并不是线程安全的, 所以多线程情况下不应共用Jedis实例, 但创建大量的Jedis会造成不必要的开销甚至对性能产生较大影响, 故使用JedisPool来避免这些问题, 它是一个线程安全的网络连接池. 可以使用它可靠地创建多个Jedis实例, 完成后将Jedis实例回收到连接池中.
  • JedisPool.getResource: 从连接池获取一个Jedis连接, 注意: Jedis使用完毕后需要调用Jedis.close方法释放资源.(Jedis实现了AutoCloseable, 推荐使用try-with-resource的写法)

Lettuce

引入依赖:

io.lettuce
lettuce-core
5.1.7.RELEASE
复制代码

Lettuce是一个可扩展的Redis客户端,用于构建非阻塞的Reactive应用程序. 它基于Netty框架构建, 性能较高, 且支持很多redis的高级特性. 目前springboot2.0已将Lettuce作为默认redis客户端. 与上一小节对应, 操作string的使用示例如下:

/** redis client */private static final RedisClient CLIENT = RedisClient.create("redis://@test-redis-server:6379/0");// test Binary-safe strings with Lettucetry (StatefulRedisConnection
connection = CLIENT.connect()) { RedisCommands
commands = connection.sync(); { // SET mykey myvalue String result = commands.set("mykey", "myvalue"); LOGGER.info("cmd: SET mykey myvalue, result: {}", result); } { // GET mykey String result = commands.get("mykey"); LOGGER.info("cmd: GET mykey, result: {}", result); } { // KEYS my* List
keys = commands.keys("my*"); LOGGER.info("cmd: KEYS my*, result: {}", JsonUtils.writeValueAsString(keys, true)); } { // EXISTS mykey Long result = commands.exists("mykey"); LOGGER.info("cmd: EXISTS mykey, result: {}", result); } { // DEL mykey Long result = commands.del("mykey"); LOGGER.info("cmd: DEL mykey, result: {}", result); } { // GET mykey String result = commands.get("mykey"); LOGGER.info("cmd: GET mykey, result: {}", result); }}复制代码

Spring 集成

spring-data-redisSpring Data家族的一部分, 提供了简单的配置以轻松访问redis, 针对存储操作提供了低级别和高级别的抽象, 将开发人员从基础实现中解放出来.

引入依赖:

org.springframework.boot
spring-boot-starter-data-redis
2.1.5.RELEASE
复制代码

使用spring-data-redis开发时, 可能最常使用的就是RedisTemplate, 所以在开始前我们先了解下RedisTemplate:

  • RedisTemplate是一个简化了Redis访问的工具类.
  • 线程安全(thread-safe), 作为单例使用即可.
  • 其实现围绕execute方法, 支持callback, 它提供的RedisConnection处理方式不需要关心连接的声明周期(简言之就是不用创建也不用关连接)

使用方法很简单, 首先在Configuration中定义StringRedisTemplate的Bean:

/** * StringRedisTemplate * @param factory * @return */@Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {    StringRedisTemplate template = new StringRedisTemplate(factory);    StringRedisSerializer serializer = new StringRedisSerializer();	// (一)    template.setKeySerializer(serializer);	// (二)    template.setHashKeySerializer(serializer);    template.setValueSerializer(serializer);    template.setHashValueSerializer(serializer);    return template;}复制代码
  • (一): RedisSerializer: 对象到二进制数组序列化和反序列化接口, 序列化和反序列化key和value, StringRedisSerializerGenericJackson2JsonRedisSerializer都是其实现.

  • (二): KeySerializer用来序列化redis key, HashKeySerializer用来序列化redis hash数据结构的field. 请勿混淆.

当然, 不要忘记了application.yml中添加redis相关配置:

spring:  redis:    host: test-redis-server    port: 6379复制代码

准备工作完成了, 现在就来体验一下, 同样地与前文对应, 操作string的使用示例如下: :

@Resourceprivate StringRedisTemplate stringRedisTemplate;/** * test Binary-safe strings with RedisTemplate */@Testpublic void testStringRedisTemplateSimple() {    {   // SET mykey myvalue        stringRedisTemplate.opsForValue().set("mykey", "myvalue");    }    {   // GET mykey        String result = stringRedisTemplate.opsForValue().get("mykey");        LOGGER.info("cmd: GET mykey, result: {}", result);    }    {   // KEYS my*        Set
keys = stringRedisTemplate.keys("my*"); LOGGER.info("cmd: KEYS my*, result: {}", JsonUtils.writeValueAsString(keys, true)); } { // EXISTS mykey Boolean result = stringRedisTemplate.hasKey("mykey"); LOGGER.info("cmd: EXISTS mykey, result: {}", result); } { // DEL mykey Boolean result = stringRedisTemplate.delete("mykey"); LOGGER.info("cmd: DEL mykey, result: {}", result); } { // GET mykey String result = stringRedisTemplate.opsForValue().get("mykey"); LOGGER.info("cmd: GET mykey, result: {}", result); }}复制代码
  • opsForValue: 获取Binary-safe strings的操作类ValueOperations( 即spring对redis操作的一个封装类. 同样地, 对hashset等也有其对应的封装HashOperationsSetOperations等).
[版权声明]
本文发布于 , 允许非商业用途转载, 但转载必须保留原作者 及链接: . 如有授权方面的协商或合作, 请联系邮箱: .

进阶

划分应用缓存

不同应用的缓存可以简单地通过key的前缀来划分

让我们来思考这样一个问题, 如果我们想要对不同应用(服务)的缓存进行划分, 以便于管理和维护, 应该如何实现?

或许增加前缀是一个不错的想法, 但如果每次编码中都需要将前缀prefix拼接到key中, 一方面增加了工作量, 另一份面也增加了出错的风险, 如果忘记拼接了怎么办. 对, 也许你也想到了, 前文提到RedisSerializerspring-data-redis对象到二进制数组序列化和反序列化接口, 用来序列化和反序列化key和value, 我们可以从这里做文章:

public interface RedisSerializer
{ /** * Serialize the given object to binary data. * * @param t object to serialize. Can be {
@literal null}. * @return the equivalent binary data. Can be {
@literal null}. */ @Nullable byte[] serialize(@Nullable T t) throws SerializationException; /** * Deserialize an object from the given binary data. * * @param bytes object binary representation. Can be {
@literal null}. * @return the equivalent object instance. Can be {
@literal null}. */ @Nullable T deserialize(@Nullable byte[] bytes) throws SerializationException;}复制代码
  • serialize: 对象 -> byte数组.
  • deserialize: byte数组 -> 对象.

RedisTemplate对redis的操作和RedisSerializer都有必然的联系, 那么可以通过实现该接口并指定RedisTemplateKeySerializer来实现增加前缀的功能. 如此一来, 增加前缀的操作就从业务中剥离出来, 对于调用方来说, 完全是透明的, 还算优雅, 具体实现如下:

/** * generic redis key serializer * @author piaoruiqing * @date: 2019-06-11 22:37 */public class GenericRedisKeySerializer implements RedisSerializer {    private final Charset charset;    private String prefix;    private int index;        public GenericRedisKeySerializer(String prefix) {        this(prefix, StandardCharsets.UTF_8);    }    public GenericRedisKeySerializer(String prefix, Charset charset) {        Assert.notNull(charset);        Assert.notNull(prefix);        this.charset = charset;        this.prefix = prefix + ":";        index = this.prefix.length();    }    @Override    public String deserialize(byte[] bytes) {                if (null == bytes) {            return null;        }        String key = new String(bytes, charset);        if (key.indexOf(prefix) == 0) {            return key.substring(index, key.length());        }        return key;    }    @Override    public byte[] serialize(Object key) {        if (null == key) {            return null;        }        String string = key.toString();        if (!string.startsWith(prefix)) {            string = prefix + string;        }        return string.getBytes(charset);    }}复制代码

将前文的StringRedisTemplate稍作修改:

@Value("${spring.application.name:undefined}")private String applicationName;/** * StringRedisTemplate * @param factory * @return */@Beanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {    StringRedisTemplate template = new StringRedisTemplate(factory);//        StringRedisSerializer serializer = new StringRedisSerializer();    GenericRedisKeySerializer serializer = new GenericRedisKeySerializer(applicationName);    template.setKeySerializer(serializer);    template.setHashKeySerializer(serializer);    template.setValueSerializer(serializer);    template.setHashValueSerializer(serializer);    return template;}复制代码
  • StringRedisSerializer替换为自定义的GenericRedisKeySerializer并指定前缀为应用名

体验一下:

stringRedisTemplate.opsForValue().set("mykey", "myvalue");String result = stringRedisTemplate.opsForValue().get("mykey");  // "myvalue"复制代码

连接到redis查看key, 已经带有前缀了

root@ubuntu:/home/ubuntu# docker exec -it redis redis-cli127.0.0.1:6379> keys *1) "redis-simple:mykey"复制代码

自定义序列化

RedisTemplate默认使用JDK序列化JdkSerializationRedisSerializer, 我们可以指定使用其他方式的序列化, 比如JSON、protostuff

前文已经描述了如何自定义key的序列化方式, value的序列化配置与其相同, 都是实现RedisSerializer并在创建RedisTemplate时指定, 就不重复贴代码了.

常用的序列化方式有几种:

  • JDK: 默认, 比较方便, 可序列化所有的类, 但速度慢且占空间较大.
  • JSON: 性能好, 输出内容比较易读.
  • Protostuff: 性能很高, 速度快且占用空间较小.

结语

本文针对redis讲解了redis java客户端的使用、与spring集成以及进阶使用, 后续将针对Redis的其他使用技巧进行讲解, 敬请关注.

系列文章

参考文献

[版权声明]
本文发布于 , 允许非商业用途转载, 但转载必须保留原作者 及链接: . 如有授权方面的协商或合作, 请联系邮箱: .

转载于:https://juejin.im/post/5cffcb2b6fb9a07ef3765f8b

你可能感兴趣的文章
《JavaScript面向对象精要》——1.5 访问属性
查看>>
《Python数据可视化编程实战》—— 第 1 章 准备工作环境
查看>>
Android应用性能优化最佳实践.1.1 Android Studio的优势
查看>>
《设计模式解析(第2版•修订版)》—第2章 2.2节什么是UML
查看>>
【直播】APP全量混淆和瘦身技术揭秘
查看>>
10个大坑,当你产品上架AppStore会遇到
查看>>
【shell 脚本】两种登录方式
查看>>
学习编程的方法
查看>>
升级linux自带的Python
查看>>
百度地图2.0瓦片地址获取(窗口内瓦片)
查看>>
我的友情链接
查看>>
.JDK1.6安装配置后的测试
查看>>
判断闰年的函数
查看>>
pkill -9 nginx
查看>>
关于ASP.NET MVC4 Web API简单总结
查看>>
BGP最新的AS号:4-byte-as 转换为十进制及AS号兼容性
查看>>
Windows2008server R2 组策略批量更改本地管理员密码
查看>>
ubutnu安装geany
查看>>
webservice 之 Java CXF实战效果 RS WS(一)
查看>>
我的友情链接
查看>>