Redis 的 JAVA 客户端
Jedis 优缺点
优点:Redis的命令就是Jedis的方法名,学习成本相对比较低。
缺点:Jedis的实力是线程不安全的,多线程环境下需要基于连接池使用
Lettuce 的优缺点
基于Netty实现的,支持同步异步和响应式编程方式,并且是线程安全的。支持Redis的哨兵模式、集群模式、管道模式。
Redissson 的优缺点
基于Redis实现的分布式、可伸缩的Java数据集合。在分布式条件下实现了Map、Queue、Lock等强大功能。
Spring Data Redis
整合了 Jedis 和 Lettuce。
Jedis 在 Maven 上的使用
Jedis 的基本使用步骤
- 引入依赖
- 创建jedis对象,并建立链接
- 使用Jedis,方法名于Redis命令一致
- 释放资源
例:
单元测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package top.zargo.test;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import redis.clients.jedis.Jedis;
import java.util.Map;
public class JedisTest { private Jedis jedis;
@BeforeEach void setUp() { jedis = new Jedis("123.207.22.15", 6379); jedis.auth("Ljj20010315_"); jedis.select(1); }
@Test void testString() { jedis.set("name", "李俊杰"); jedis.set("age", "23"); String name = jedis.get("name"); String age = jedis.get("age"); System.out.println(name); System.out.println(age); }
@Test void testHash() { jedis.hset("user:1", "name", "李俊杰"); jedis.hset("user:1", "age", "24"); String name = jedis.hget("user:1", "name"); String age = jedis.hget("user:1", "age"); System.out.println(name); System.out.println(age); Map<String, String> stringStringMap = jedis.hgetAll("GoldPrice:itemName:Gold"); System.out.println(stringStringMap); }
@AfterEach void tearDown() { if(jedis != null) { jedis.close(); } } }
|
Jedis本身是线程不安全的,频繁的创建和销毁链接会有性能的损耗,因此建议使用连接池来代替Jedis的直连。
Jedis 的连接池
首先建立一个工具类用来创建链接池,用static final创建静态的JedisPool对象,并使用static{}静态代码块完成对象初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class jedisConnectionFactory { private static final JedisPool jedisPoll; static { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxTotal(8); jedisPoolConfig.setMaxIdle(8); jedisPoolConfig.setMinIdle(0); jedisPoolConfig.setMaxWait(Duration.ofMillis(200)); jedisPoll = new JedisPool(jedisPoolConfig, "123.207.22.15", 6379,1000,"Ljj20010315_"); } public static Jedis getJedis() { return jedisPoll.getResource(); } }
|
在连接池工具类创建完成之后,在测试类中进行调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @BeforeEach void setUp() { jedis = jedisConnectionFactory.getJedis(); jedis.select(1); } @Test void test() { } @AfterEach void tearDown() { if(jedis != null) { jedis.close(); } }
|
使用连接池关闭链接后,并不会真正的关闭链接,而是把资源归还连接池。
链接池的 close() 方法重写了,当具有连接池的时候:
if (dataSource != null)
直接把资源归还给连接池:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Override public void close() { if (dataSource != null) { Pool<Jedis> pool = this.dataSource; this.dataSource = null; if (isBroken()) { pool.returnBrokenResource(this); } else { pool.returnResource(this); } } else { connection.close(); } }
|
SpringDataRedis
SpringData是Spring中数据操作的模块,包含着对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis。
SpringDataRedis的特性
- 提供了对不同Java Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化和反序列化
- 支持基于Redis的JDKCollection实现
SpringDataRedis的使用
- 在maven的pom文件中引入sping-boot-starter-data-redis的依赖。(在springboot的依赖引入界面中选择SpringDataRedis即可)在新版本的SpringDataRedis中是包含common-pool2的,但是我们还是可以在pom文件中手动引入common-pool2依赖。
- 在src.main.resources.application.yaml文件中写好配置:
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: data: redis: host: 123.207.22.15 port: 6379 password: Ljj20010315_ database: 1 lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0 max-wait: 200ms
|
- 在类中注入依赖,直接使用:
1 2 3 4 5 6 7 8 9 10 11
| class SpringdataReidsDemoApplicationTests { @Autowired private RedisTemplate redisTemplate;
@Test void testString() { redisTemplate.opsForValue().set("price",21); Object price = redisTemplate.opsForValue().get("price"); System.out.println(price); } }
|
RedisTemplate的序列化
当我们使用RedisTemplate对redis库进行set操作的时候,他会将我们传入的数据转化成序列化对象进行存储。
这是SpringDataRedis的特殊功能,它可以保存任何对象,自动进行序列化和反序列化。
当我们调用RedisTemplate的set方法的时候,传的参数是一个Object类的对象。