目前我了解到的有以下 4 种。
Spring Data Redis
1.介绍
SpringData 是 Spring 中数据操作的模块,包含对各种数据库的集成,相当于定义了一些如增删改查的抽象接口,继而有对应不同数据库的实现。
其中对 redis 集成模块就叫做 Spring Data Redis。
- 提供了对不同 Redis 客户端的整合(Lettuce 和 Jedis)
- 提供了 RedisTemplate 统一 API 来操作 Redis
- 支持 Redis 的发布订阅模型
- 支持 Redis 哨兵和 Redis 集群
- 支持基于 Lettuce 的响应式编程
- 支持基于 JDK.JSON.字符串.Spring 对象的数据序列化及反序列化
- 支持基于 Redis 的 JDKCollection 实现
SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作 API 封装到了不同的类型中:
2.使用
2.1 引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency>
|
2.2 编写配置文件
1 2 3 4 5 6 7 8 9 10 11
| spring: redis: host: localhost port: 6379 password: yourPassword lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 max-wait: 100ms
|
2.3 测试与问题
可以看到是可以正常写入和获取的,那么我们来看看数据库。
发现问题:
- 插入进来的怎么不是“coderbin”,多了前面一坨东西呢?
- 为什么查不到值呢?
追溯问题:
RedisTemplate 可以接收任意 Object 作为值写入 Redis,只不过写入前会把 Object 序列化为字节形式,默认是采用JDK序列化
,得到的结果就是上图所示
2.4 解决序列化问题
简单方法:直接不用 RedisTemplate,我们用StringRedisTemplate.
正常输出,再去看数据库。
键值的数据也是正常的,但是!这里又有问题。
stringRedisTemplate 的 set 方法要求键值都为 string 类型,这就无法满足我们的需求。
那么我们就要自定义 RedisTemplate 的序列化方式啦!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Component public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer(); template.setKeySerializer(RedisSerializer.string()); template.setHashKeySerializer(RedisSerializer.string()); template.setValueSerializer(jsonRedisSerializer); template.setHashValueSerializer(jsonRedisSerializer); return template; } }
|
可以看到已经大功告成了。
总结一下:
RedisTemplate 的两种序列化实践方案:
方案一:
- 自定义 RedisTemplate
- 修改 RedisTemplate 的序列化器为 GenericJackson2JsonRedisSerializer
方案二:
- 使用 StringRedisTemplate
- 写入 Redis 时,手动把对象序列化为 JSON
- 读取 Redis 时,手动把读取到的 JSON 反序列化为对象
Jedis
(25 条消息) Jedis 常用方法 API_遛狗大师的博客-CSDN 博客_jedis 方法
使用阻塞的 I/O,且其方法调用都是同步的(慢!),程序流需要等到 sockets 处理完 I/O 才能执行,不支持异步。Jedis 客户端实例不是线程安全的,所以需要通过连接池来使用 Jedis。
1.快速入门
1.1 引入依赖
1 2 3 4 5 6
| <!--jedis--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> </dependency>
|
1.2 创建连接池
Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用 Jedis 连接池代替 Jedis 的直连方式
有关池化思想,并不仅仅是这里会使用,很多地方都有,比如说我们的数据库连接池,比如我们 tomcat 中的线程池,这些都是池化思想的体现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class JedisConnectionFacotry { private static final JedisPool jedisPool;
static { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(8); poolConfig.setMaxIdle(8); poolConfig.setMinIdle(0); poolConfig.setMaxWaitMillis(1000); jedisPool = new JedisPool(poolConfig, "localhost",6379,1000); }
public static Jedis getJedis(){ return jedisPool.getResource(); } }
|
1.3 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @BeforeEach void setUp(){ jedis = JedisConnectionFacotry.getJedis(); jedis.select(0); } @Test void testHash() { jedis.hset("user:1", "name", "Jack"); jedis.hset("user:1", "age", "21");
Map<String, String> map = jedis.hgetAll("user:1"); System.out.println(map); } @AfterEach void tearDown() { if (jedis != null) { jedis.close(); } }
|
测试成功!
Redisson
Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的 Java 常用对象,还提供了许多分布式服务。Redisson 的宗旨是促进使用者对 Redis 的关注分离(Separation of Concern),从而让使用者能够将精力更集中地放在处理业务逻辑上。
1.快速入门
1.1 引入依赖
1 2 3 4 5
| <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.13.6</version> </dependency>
|
1.2 配置 Redisson 客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration public class RedissonConfig {
@Bean public RedissonClient redissonClient(){ Config config = new Config(); config.useSingleServer().setAddress("redis://192.168.150.101:6379") .setPassword("123321"); return Redisson.create(config); } }
|
1.3 使用 Redission 的分布式锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Resource private RedissionClient redissonClient;
@Test void testRedisson() throws Exception{ RLock lock = redissonClient.getLock("anyLock"); boolean isLock = lock.tryLock(1,10,TimeUnit.SECONDS); if(isLock){ try{ System.out.println("执行业务"); }finally{ lock.unlock(); }
} }
|
Redisson 有非常多的分布式服务:
具体的各个用法需要结合官网和你的具体业务实现。
Java 客户端总结
- 如果使用了 Spring,并且没有过多的定制化要求,那么大可以选择 Spring Data Redis
- 如果没有使用 Spring,只需要实现简单的业务,也没有过高的性能要求,那么可以选择 Jedis
- 如果没有使用 Spring,并且追求高性能、高定制化,可以用 Lettuce,支持异步、连接池
- 如果项目是分布式架构,需要一些分布式服务(分布式锁,分布式集合等等),那么可以选择 Redisson