学习Redis第二天
在Redis官网中提供了各种语言的客户端,地址:https://redis.io/clients
学习Redis的Java客户端的使用:
Jedis
SpringDataRedis
文章目录
前言
主要内容:
1、Java客户端的种类;
2、Jedis的快速入门;
3、Jedis的连接池;
4、认识SpringDataRedis;
5、RedisTemplate快速入门;
6、RedisTemplate的RedisSerializer(序列化工具);
7、StringRedisTemplate;(序列化工具)
1、Java客户端的种类;
- Jedis :以Redis命令作为方法名称,学习成本低,简单实用。但是Jedis实例是线程不安全的,多线程环境下需要基于连接池使用。
- lettuce:lettuce是基于Netty实现的,支持同步、异步和响应式编程,并且是线程安全的。支持Redis的哨兵模式、集群模式和管道模式。(Spring默认兼容的客户端)
- Redisson:Redisson是一个基于Redis实现的分布式、可伸缩的Java数据结构集合、包含了诸如Map、Queue、Lock、Semaphore、AtomicLong等强大功能;
- Spring整合了Jedis和lettuce----Spring Data Redis。
2、Jedis的快速入门;
Jedis的官网地址:https://github.com/redis/jedis
快速入门(5步):
1.先创建一个Maven工程:
2.在pom.xml中导入Jedis依赖:(引入junit是为了方便测试)
3.建立与Redis的连接:
public class JedisTest {
//先创建Jedis对象
private Jedis jedis;
@BeforeEach
void setUp(){
//建立连接,ip地址是自己虚拟机的ip地址
jedis = new Jedis("192.168.152.25",6379);
//密码,自己的密码
this.jedis.auth("123456");
//选择数据库(0-15),默认0号库
this.jedis.select(0);
}
4.测试:以操作String为例
@Test
void testString(){
//存入数据
String result = jedis.set("name", "xiaoxin");
System.out.println("result = " + result);
String name = jedis.get("name");
System.out.println("name = " + name);
}
测试结果:
证明连接成功并且可以成功写入数据;也可以看出Jedis所使用的对数据操作的命令是和Redis一模一样的。
5.关闭资源
@AfterEach
void tearDown(){
if (jedis!=null){
jedis.close();
}
}
3、Jedis的连接池;
Jedis直接连接的缺点:Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此可以使用Jedis连接池代替Jedis直连方式。
创建连接池的方法:
1.可以创建一个工具包然后在里面创建一个连接工厂:
public class JedisConnectionFactory {
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,
"192.168.152.25", 6379, 1000, "123456");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
2.测试:
把直接连接修改为使用Jedis连接池连接
//建立连接
//jedis = new Jedis("192.168.152.25",6379);
//使用连接池连接
jedis = JedisConnectionFactory.getJedis();
测试:
@Test
void testString(){
//存入数据
String result = jedis.set("test", "xiaoxin");
System.out.println("result = " + result);
String test = jedis.get("test");
System.out.println("test = " + test);
}
-结果–
4、认识SpringDataRedis
简介:
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫SpringDataRedis,官网地址:https://spring.io/projects/spring-data-redis
内容:
1.提供了对不同Redis客户端的整合(Lettuce和Jedis);
2.提供了RedisTemplate统一API来操作Redis;
3.支持Redis的发布订阅模型;
4.支持基于Lettuce的响应式编程;
5.支持Redis哨兵和Redis集群;
6.支持基于JDK、JSON、字符串、Spring对象的数据序列化和反序列化;
7.支持基于Redis的JDKCollection实现。
5、SpringDataRedis快速入门:
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作,并且将不同的数据类型的操作API封装到了不同的类型中:
SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单:
1、创建SpringBoot工程:
勾选上SpringDataRedis:
2、导入依赖:
勾选之后会自动导入依赖:(里面一些其他的依赖是因为勾选了一些工具后也自动导入了)
<dependencies>
<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>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
其中最重要的依赖是Redis依赖和连接池依赖:
3、配置文件:
在resources目录下创建一个application.yaml文件,里面配置一些关于连接Redis的信息(如ip地址,密码,连接池信息等)
4、注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
5、编写测试
@SpringBootTest
class ReidsDemoApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString() {
//写入一条数据
redisTemplate.opsForValue().set("name","小飞");
//获取写入数据的值
Object name = redisTemplate.opsForValue().get("name");
System.out.println("name = " + name);
}
}
测试结果:
6、RedisTemplate的RedisSerializer(序列化工具)
RedisTemplate的序列化问题:
在使用RedisTemplate来操作数据时,默认的操作方式是把数据都当成一个对象进行写入,如key-value都是Object类型:
这就会导致存储在Redis中存储的数据都是经过RedisTemplate序列化之后在存储进去的,当我们在Redis中查看数据时会发现:
在name中存储的是一个经过序列化的字符串。
这个问题的缺点:
·可读性差
·内存占用较大
解决方法:改变RedisTemplate的序列化方式。
自定义RedisTemplate的序列化方式,代码如下:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//创建RedisTemplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
//设置连接工厂
template.setConnectionFactory(connectionFactory);
//创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//设置key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
//设置value的序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
//返回
return template;
}
}
测试写入一个对象:
先创建一个对象:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private Integer age;
}
写入对象:
@Test
void testSaveUser(){
redisTemplate.opsForValue().set("MyObject",new User("小飞",21));
User o = (User) redisTemplate.opsForValue().get("MyObject");
System.out.println("o = " + o);
}
控制台打印的结果:
在图形化工具查看结果:
可以看到已经成功写入,并且在获取结果打印到控制台时,还能反序列化成User对象。
如何反序列化的:可以看到在写入对象时,还写入了Class这个属性,对应的就是对象的字节码名称,在反序列化才能读取到这个类的名称,然后再反序列化。
7、StringRedisTemplate;(序列化工具)
问题:虽然这样的序列化方式可以满足需求,但是在反序列化的过程中为了要知道对象的类型,JSON序列化器会将类的class类型写入json结果中,存入Redis,会带来额外的内存开销。
解决方案:为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。如图:
这样的话又要重新定义StringRedisTemplate,好消息是,Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式,省去了我们自定义RedisTemplate的过程,直接注入StringredisTemplate就可以使用了:
@Autowired
private StringRedisTemplate stringRedisTemplate;
//JSON工具,作用就是把一个对象转JSON
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testSaveUser() throws JsonProcessingException {
//创对象
User user = new User("小兔子", 12);
//手动序列化对象
String json = mapper.writeValueAsString(user);
//写入数据
stringRedisTemplate.opsForValue().set("name",json);
//取出数据
String jsonUser = stringRedisTemplate.opsForValue().get("name");
//反序列化
User user1 = mapper.readValue(jsonUser, User.class);
System.out.println("user1 = " + user1);
}
图形化工具查看结果:
控制台打印的结果:
总结两种方案:
总结
学习了Redis的java客户端Jedis和SpringDataRedis的使用,并解决了一些用法上的问题。