常用的redis客户端介绍以及对比
Jedis api 在线网址:http://tool.oschina.net/uploads/apidocs/redis/clients/jedis/Jedis.html
redisson 官网地址:https://redisson.org/
redisson git项目地址:https://github.com/redisson/redisson
lettuce 官网地址:https://lettuce.io/ lettuce
git项目地址:https://github.com/lettuce-io/lettuce-core
首先,在spring boot2之后,对redis连接的支持,默认就采用了lettuce。这就一定程度说明了lettuce 和Jedis 的优劣。
概念
Jedis:是老牌的Redis的Java实现客户端,提供了比较全面的Redis命令的支持,
Redisson:实现了分布式和可扩展的Java数据结构。
Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。
优点
Jedis:比较全面的提供了Redis的操作特性
Redisson:促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过 Redis支持延迟队列
Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操 作单个Lettuce连接来完成各种操作
可伸缩
Jedis:使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。 Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。
Redisson:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以 操作单个Redisson连接来完成各种操作
Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操 作单个Lettuce连接来完成各种操作
lettuce能够支持redis4,需要java8及以上。 lettuce是基于netty实现的与redis进行同步和异步的通信。
lettuce和jedis比较
jedis使直接连接redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个jedis实 例增加物理连接 ;
lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问, StatefulRedisConnection是线程安全的,所以一个连接实例可以满足多线程环境下的并发访问,当然这也是可伸 缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排 序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力 更集中地放在处理业务逻辑上。
总结
优先使用Lettuce,如果需要分布式锁,分布式集合等分布式的高级特性,添加Redisson结合使用,因为Redisson 本身对字符串的操作支持很差。
在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好,库存数量 可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加 锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。 那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis官方推荐使用的Redisson就提供了分布式锁和 相关服务。
在官方网站列一些Java客户端访问,有:Jedis/Redisson/Jredis/JDBC-Redis等,其中官方推荐使用Jedis和 Redisson。常用Jedis。
简介
我们在使用springboot搭建微服务的时候,在很多时候还是需要redis的高速缓存来缓存一些数据,存储一些高频率 访问的数据,如果直接使用redis的话又比较麻烦,在这里,我们使用jedis来实现redis缓存来达到高效缓存的目的
新建一个spring项目
引入Jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
因为 SpringBoot 内默认引用了jedis版本。
所以我们直接引入jedis 依赖 无需在配置 jedis的版本号了
完成的pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.fjx</groupId>
<artifactId>boot-jedis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>boot-jedis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml配置文件
server:
port: 8080
spring:
redis:
host: 192.168.22.165
port: 6379
password: fengjiaxing
jedis:
pool:
max-idle: 6 #最大空闲数
max-active: 20 #最大连接数
min-idle: 2 #最小空闲数
timeout: 2000 #连接超时
新建JedisConfig配置类
package com.fjx.config;/*
@author Jason
@DESCRIPTION
@create 2020-01-08
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
@Configuration //相当于一个XML
public class JedisConfig {
private Logger logger = LoggerFactory.getLogger(JedisConfig.class);
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean
public JedisPool jedisPool(){
JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setMaxTotal(maxActive);
JedisPool jedisPool =new JedisPool(jedisPoolConfig,host,port,timeout,password);
logger.info("JedisPool连接成功:"+host+"\t"+port);
return jedisPool;
}
}
新写测试类
package com.fjx;
import com.fjx.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@SpringBootTest
class BootJedisApplicationTests {
@Autowired
private JedisPool jedisPool;
@Test
void contextLoads() {
System.out.println(jedisPool);
}
}
项目目录
新建user实体对象 User类
package com.fjx.pojo;/*
@author Jason
@DESCRIPTION
@create 2020-01-08
*/
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
private String id;
private String username;
private Integer age;
}
新建UserService接口
package com.fjx.service;/*
@author Jason
@DESCRIPTION
@create 2020-01-08
*/
import com.fjx.pojo.User;
public interface UserService {
/**
* @author Jason
* @DESCRIPTION: ******TODO 测试string类型
* Redis String类型学习
* 需求: 用户输入一个key,获取value值
* 先判断Redis中是否存在该数据
* 如果存在.redis 中进行查询,结果返回
* 如果不存在,mysql数据库中查询,将结果复制个redis,并返回
* @params: [key]
* @return: java.lang.String
* @Date: 2020-01-09 15:33
* @Modified By:
*/
String getString(String key);
/**
* @author Jason
* @DESCRIPTION: ******TODO 测试hash类型
* Redis hash类型学习
* 需求: 根据id查询用户信息
* 先判断Redis中是否存在该数据
* 如果存在.redis 中进行查询,并返回
* 如果不存在,mysql数据库中查询,将结果复制个redis,并返回
* @params: [id]
* @return: com.fjx.pojo.User
* @Date: 2020-01-11 10:29
* @Modified By:
*/
User selectById(String id);
}
新建UserServiceImpl实现类,实现UserService接口
package com.fjx.service.impl;/*
@author Jason
@DESCRIPTION
@create 2020-01-09
*/
import com.fjx.config.JedisUtils;
import com.fjx.pojo.User;
import com.fjx.service.UserService;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Map;
@Service
@Log
public class UserServiceImpl implements UserService {
@Autowired
private JedisUtils jedisUtils;
/**
* @author Jason
* @DESCRIPTION: redis有什么命令,jedis就有什么方法
* @params: [key]
* @return: java.lang.String
* @Date: 2020-01-09 16:29
* @Modified By:
* ***********TODO String类型演示
*/
@Override
public String getString(String key) {
Jedis jedis = jedisUtils.getJedis();
String val = null;
if (!jedis.exists(key)) {
val = "范闲";
log.info(key + "数据来自mysql数据库,值为:" + val);
jedis.set(key, val);
log.info(key + "将数据库中的数据存入redis" + val);
} else {
val = jedis.get(key);
log.info(key + "数据来自redis,值为" + val);
}
jedisUtils.close(jedis);
return val;
}
/**
* @author Jason
* @DESCRIPTION: 根据id查询用户信息
* **TODO 测试hash类型
* @params: [id]
* @return: com.fjx.pojo.User
* @Date: 2020-01-11 10:32
* @Modified By:
*/
@Override
public User selectById(String id) {
// 思路
// 1.获取连接对象
Jedis jedis = jedisUtils.getJedis();
String key = "user:id";
User user = new User();
// 如果redis中不存在该key值
if (!jedis.exists(key)) {
// 封装一个用户对象
user.setId(id);
user.setUsername("哭泣巴拉");
user.setAge(11);
//从数据库中进行查询
log.info("从mysql数据库中查询用户信息" + user);
// 将查询出来的数据存入到redis
HashMap<String, String> map = new HashMap<>();
map.put("id", user.getId());
map.put("name", user.getUsername());
jedis.hset(key, map);
log.info(key + "成功将用户信息存入redis" + user);
} else {
// 从redis中查询用户信息
Map<String, String> map = jedis.hgetAll(key);
user.setId(map.get("id"));
user.setUsername(map.get("name"));
log.info(key + "从redis中查询用户信息" + map);
}
// 关闭连接对象
jedisUtils.close(jedis);
return user;
}
}
编写测试类
package com.fjx;
import com.fjx.pojo.User;
import com.fjx.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
@SpringBootTest
class BootJedisApplicationTests {
@Autowired
private JedisPool jedisPool;
@Test
void contextLoads() {
System.out.println(jedisPool);
}
@Autowired
private UserService userService;
/**
* @author Jason
* @DESCRIPTION: 用户输入一个key,获取value值
* TODO 测试String类型
* @params: []
* @return: void
* @Date: 2020-01-11 10:51
* @Modified By:
*/
@Test
void stringTest() {
String result = userService.getString("username");
System.out.println(result);
}
/**
* @author Jason
* @DESCRIPTION:根据用户id查询用户信息
* TODO 测试Hash类型
* @params: []
* @return: void
* @Date: 2020-01-11 10:50
* @Modified By:
*/
@Test
void hashTest() {
User user = userService.selectById("1001");
System.out.println(user);
}
}
运行结果
来源:CSDN
作者:冯佳兴
链接:https://blog.csdn.net/fjxcsdn/article/details/104065811