一、Jedis
Jedis是一个Java实现的Redis客户端连接工具。
Jedis使用非常简单,直接引入依赖。基于默认参数的Jedis连接池,初始化连接池类(使用默认连接池参数)JedisPool,获取一个Jedis连接Jedis jedis=jp.getResource()。
Jedis是线程不安全的,多线程使用同一个Jedis实例,会出现并发问题,原因是底层共用了一个输入输出流
1.1 Jedis快速入门
Jedis的官网地址: GitHub - redis/jedis: Redis Java client,我们先来个快速入门:
① 新建一个Maven工程并引入以下依赖
<!--引入Jedis依赖-->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.2.0</version>
</dependency><!--引入单元测试依赖-->
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.8.2</version><scope>test</scope>
</dependency>
② 编写测试类并与Redis建立连接
private Jedis jedis;@BeforeEach //被该注解修饰的方法每次执行其他方法前自动执行
void setUp(){// 1. 获取连接jedis = new Jedis("192.168.230.88",6379);// 2. 设置密码jedis.auth("132537");// 3. 选择库(默认是下标为0的库)jedis.select(0);
}
③ 编写一个操作数据的方法(这里以操作String类型为例)
@Test
public void testString(){// 1.往redis中存放一条String类型的数据并获取返回结果String result = jedis.set("url", "https://www.oz6.cn");System.out.println("result = " + result);// 2.从redis中获取一条数据String url = jedis.get("url");System.out.println("url = " + url);
}
④ 最后不要忘记编写一个释放资源的方法
@AfterEach //被该注解修饰的方法会在每次执行其他方法后执行void tearDown(){// 1.释放资源if (jedis != null){jedis.close();}}
⑤ 执行testString()
方法后测试结果如图所示
1.2 Jedis连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
public class JedisConnectionFactory {private static final JedisPool jedisPool;static {//配置连接池JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();jedisPoolConfig.setMaxTotal(8);jedisPoolConfig.setMaxIdle(8);jedisPoolConfig.setMinIdle(0);jedisPoolConfig.setMaxWaitMillis(200);//创建连接池对象jedisPool = new JedisPool(jedisPoolConfig,"192.168.230.88",6379,1000,"132537");}public static Jedis getJedis(){return jedisPool.getResource();}
}
二、SpringDataRedis介绍
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做
SpringDataRedis
官网地址:Spring Data Redis
-
提供了对不同Redis客户端的整合(
Lettuce
和Jedis
) -
提供了
RedisTemplate
统一API来操作Redis -
支持Redis的发布订阅模型
-
支持Redis哨兵和Redis集群
-
支持基于Lettuce的响应式编程
-
支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
-
支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
三、SpringDataRedis快速入门
SpringBoot
已经提供了对SpringDataRedis
的支持,使用非常简单
① 首先新建一个Spring Boot工程
② 然后引入连接池依赖
<!--连接池依赖-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
③ 编写配置文件application.yml
(连接池的配置在实际开发中是根据需求来的)
spring:redis:host: 192.168.230.88 #指定redis所在的hostport: 6379 #指定redis的端口password: 132537 #设置redis密码lettuce:pool:max-active: 8 #最大连接数max-idle: 8 #最大空闲数min-idle: 0 #最小空闲数max-wait: 100ms #连接等待时间
④ 编写测试类执行测试方法
@SpringBootTest
class RedisDemoApplicationTests {@Resourceprivate RedisTemplate redisTemplate;@Testvoid testString() {// 1.通过RedisTemplate获取操作String类型的ValueOperations对象ValueOperations ops = redisTemplate.opsForValue();// 2.插入一条数据ops.set("blogName","Vz-Blog");// 3.获取数据String blogName = (String) ops.get("blogName");System.out.println("blogName = " + blogName);}
}
四、RedisSerializer配置
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,
默认是采用JDK序列化
,得到的结果是这样的
缺点:
-
可读性差
-
内存占用较大
那么如何解决以上的问题呢?我们可以通过自定义RedisTemplate序列化的方式来解决。
编写一个配置类RedisConfig
:
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){// 1.创建RedisTemplate对象RedisTemplate<String ,Object> redisTemplate = new RedisTemplate<>();// 2.设置连接工厂redisTemplate.setConnectionFactory(factory);// 3.创建序列化对象StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// 4.设置key和hashKey采用String的序列化方式redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);// 5.设置value和hashValue采用json的序列化方式redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);return redisTemplate;}
}
此时我们已经将RedisTemplate的key设置为
String序列化
,value设置为Json序列化
的方式,再来执行方法测试
由于我们设置的value序列化方式是Json的,因此我们可以直接向redis中插入一个对象
@Test
void testSaveUser() {redisTemplate.opsForValue().set("user:100", new User("Vz", 21));User user = (User) redisTemplate.opsForValue().get("user:100");System.out.println("User = " + user);
}
尽管Json序列化可以满足我们的需求,但是依旧存在一些问题。
如上图所示,为了在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
那么我们如何解决这个问题呢?我们可以通过下文的StringRedisTemplate
来解决这个问题。
五、StringRedisTemplate
为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程
我们可以直接编写一个测试类使用StringRedisTemplate来执行以下方法:
@SpringBootTest
class RedisStringTemplateTest {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Testvoid testSaveUser() throws JsonProcessingException {// 1.创建一个Json序列化对象ObjectMapper objectMapper = new ObjectMapper();// 2.将要存入的对象通过Json序列化对象转换为字符串String userJson1 = objectMapper.writeValueAsString(new User("Vz", 21));// 3.通过StringRedisTemplate将数据存入redisstringRedisTemplate.opsForValue().set("user:100",userJson1);// 4.通过key取出valueString userJson2 = stringRedisTemplate.opsForValue().get("user:100");// 5.由于取出的值是String类型的Json字符串,因此我们需要通过Json序列化对象来转换为java对象User user = objectMapper.readValue(userJson2, User.class);// 6.打印结果System.out.println("user = " + user);}}
执行完毕回到Redis的图形化客户端查看结果 :
六、总结
RedisTemplate的两种序列化实践方案,两种方案各有各的优缺点,可以根据实际情况选择使用。
方案一:
-
自定义RedisTemplate
-
修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
方案二:
-
使用StringRedisTemplate
-
写入Redis时,手动把对象序列化为JSON
-
读取Redis时,手动把读取到的JSON反序列化为对象