操作系统:CentOS-7.8
Redis版本:6.0.5
SpringBoot 2.1.5.RELEASE
Java Version 1.8.0_231
本篇内容主要演示在Java代码中连接和使用Redis,对Redis不熟悉的朋友可以先看前两篇《一起学习Redis基础》和《一起学习Redis高可用》,本篇涉及到的代码完整版github地址为:https://github.com/telundusiji/dream-hammer/tree/master/module-6
Jedis、Redisson和Lettuce都是比较常用的支持连接Redis的客户端,所以在这里我们主要演示这三种客户端如何连接不同的redis模式的redis
比较经典的Redis的Java客户端,对Redis的命令支持比较全面
比较轻量和简洁,对其进行改造和集成比较方便
不支持异步,方法调用都是同步的,使用的阻塞IO
客户端实例非线程安全,多线程并发场景下,需要通过连接池来使用客户端
早期版本Spring的默认客户端
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>2.9.3version>
dependency>
import redis.clients.jedis.Jedis;
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class SingleInstanceJedis {
private String host;
private Integer port;
private String password;
/**
* 连接单机单实例的redis
*
* @param host redis主机地址
* @param port redis服务端口
* @param password redis认证密码
*/
public SingleInstanceJedis(String host, Integer port, String password) {
this.host = host;
this.port = port;
this.password = password;
}
/**
* 连接redis
*
* @return 一个Jedis客户端
*/
public Jedis connect() {
Jedis jedis = new Jedis(host, port);
jedis.auth(password);
return jedis;
}
}
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import java.util.Set;
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class SentinelJedis {
private JedisSentinelPool jedisSentinelPool;
/**
* 连接哨兵模式的redis
*
* @param masterName redis的master名称
* @param sentinels 哨兵的主机和端口信息
* @param password redis的认证密码
*/
public SentinelJedis(String masterName, Set<String> sentinels, String password) {
//根据redis的信息创建一个redis哨兵的连接池
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(10);
config.setMaxIdle(5);
config.setMinIdle(5);
jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, config, password);
}
/**
* 从连接池中取出一个客户端
*
* @return 获取一个Jedis客户端
*/
public Jedis connect() {
return jedisSentinelPool.getResource();
}
/**
* 销毁连接池
*/
public void close() {
jedisSentinelPool.close();
jedisSentinelPool.destroy();
}
}
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.Set;
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class ClusterJedis {
private Set<HostAndPort> redisNodes;
private String password;
private GenericObjectPoolConfig config;
/**
* 连接redis cluster
*
* @param redisNodes 集群中redis节点信息
* @param password redis 密码
*/
public ClusterJedis(Set<HostAndPort> redisNodes, String password) {
this.redisNodes = redisNodes;
this.password = password;
config = new GenericObjectPoolConfig();
config.setMaxTotal(10);
config.setMaxIdle(5);
config.setMinIdle(5);
}
/**
* 连接redis cluster
*
* @return 一个redis cluster客户端
*/
public JedisCluster connect() {
JedisCluster jedisCluster = new JedisCluster(redisNodes, 10000, 10000, 3, password, config);
return jedisCluster;
}
}
以上三段代码是使用Jedis连接三种模式下Redis的简易演示代码,下面再附上测试类代码
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class JedisTest {
private static final Logger LOGGER = LoggerFactory.getLogger(JedisTest.class);
private static final String TEST_KEY = "jedis";
private static final String TEST_VALUE = "dream-hammer";
@Test
public void singleInstance() {
SingleInstanceJedis singleInstanceJedis = new SingleInstanceJedis("192.168.56.90", 6379, "123456");
Jedis jedis = singleInstanceJedis.connect();
jedis.set(TEST_KEY, TEST_VALUE);
LOGGER.info("jedis单机单实例:{}", jedis.get(TEST_KEY));
Assert.assertEquals(TEST_VALUE, jedis.get(TEST_KEY));
}
@Test
public void sentinel() {
Set<String> sentinels = new HashSet<>();
sentinels.add("192.168.56.91:26379");
sentinels.add("192.168.56.92:26379");
sentinels.add("192.168.56.93:26379");
SentinelJedis sentinelJedis = new SentinelJedis("redis-master", sentinels, "123456");
Jedis jedis = sentinelJedis.connect();
jedis.set(TEST_KEY, TEST_VALUE);
LOGGER.info("jedis哨兵模式:{}", jedis.get(TEST_KEY));
Assert.assertEquals(TEST_VALUE, jedis.get(TEST_KEY));
}
@Test
public void cluster() {
Set<HostAndPort> redisNodes = new HashSet<>();
redisNodes.add(new HostAndPort("192.168.56.81",6379));
redisNodes.add(new HostAndPort("192.168.56.82",6379));
redisNodes.add(new HostAndPort("192.168.56.83",6379));
redisNodes.add(new HostAndPort("192.168.56.84",6379));
redisNodes.add(new HostAndPort("192.168.56.85",6379));
redisNodes.add(new HostAndPort("192.168.56.86",6379));
ClusterJedis clusterJedis = new ClusterJedis(redisNodes, "123456");
JedisCluster jedisCluster = clusterJedis.connect();
jedisCluster.set(TEST_KEY, TEST_VALUE);
LOGGER.info("jedis集群模式:{}", jedisCluster.get(TEST_KEY));
Assert.assertEquals(TEST_VALUE, jedisCluster.get(TEST_KEY));
}
}
基于Netty实现,使用非阻塞IO,支持异步,性能高
API是线程安全的,可以操作单个Redisson连接来完成多种操作
实现多种分布式和可扩展的Java数据结构,例如,分布式锁,分布式集合,可通过Redis支持延迟队列
Redisson注重分布式和锁的相关功能,所以在基础功能上较为简单,不支持Redis的原生命令操作,比如不支持字符串操作等
<dependency>
<groupId>org.redissongroupId>
<artifactId>redissonartifactId>
<version>3.12.5version>
dependency>
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class SingleInstanceRedisson {
private Config config;
/**
* 连接单机单实例的redis
*
* @param host redis主机地址
* @param port redis 端口
* @param password redis密码
*/
public SingleInstanceRedisson(String host, Integer port, String password) {
config = new Config();
config.useSingleServer()
.setAddress("redis://" + host + ":" + port)
.setPassword(password);
}
/**
* 连接redis
*
* @return 一个RedissonClient客户端
*/
public RedissonClient connect() {
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class SentinelRedisson {
private Config config;
/**
* 连接哨兵模式redis
*
* @param masterName redis的master名称
* @param sentinels 哨兵的连接信息 redis://sentinelHost:sentinelPort
* @param password redis密码
*/
public SentinelRedisson(String masterName, String[] sentinels, String password) {
config = new Config();
config.useSentinelServers()
.setMasterName(masterName)
.addSentinelAddress(sentinels)
.setPassword(password);
}
/**
* 连接redis
*
* @return 一个RedissonClient客户端
*/
public RedissonClient connect() {
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
/**
* @author 爱做梦的锤子
* @create 2020/7/17
*/
public class ClusterRedisson {
private Config config;
/**
* 连接cluster模式的redis
*
* @param redisNodes redis集群中节点信息 redis://nodeHost:nodePort
* @param password redis密码
*/
public ClusterRedisson(String[] redisNodes, String password) {
config = new Config();
config.useClusterServers()
.addNodeAddress(redisNodes)
.setPassword(password);
}
/**
* 连接redis
*
* @return 一个RedissonClient客户端
*/
public RedissonClient connect() {
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}
以上三段代码是使用Redisson连接三种模式下Redis的简易演示代码,下面再附上测试类代码
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
public class RedissonTest {
private static final Logger LOGGER = LoggerFactory.getLogger(RedissonTest.class);
private static final String TEST_KEY = "redisson";
private static final long TEST_VALUE = 100L;
@Test
public void singleInstance() {
SingleInstanceRedisson singleInstanceRedisson = new SingleInstanceRedisson("192.168.56.90", 6379, "123456");
RedissonClient redissonClient = singleInstanceRedisson.connect();
RAtomicLong atomicLong = redissonClient.getAtomicLong(TEST_KEY);
atomicLong.set(TEST_VALUE);
LOGGER.info("redisson单机单实例:{}", redissonClient.getAtomicLong(TEST_KEY).get());
Assert.assertEquals(TEST_VALUE, redissonClient.getAtomicLong(TEST_KEY).get());
}
@Test
public void sentinel() {
String[] sentinels = new String[]{"redis://192.168.56.91:26379", "redis://192.168.56.92:26379", "redis://192.168.56.93:26379"};
SentinelRedisson sentinelRedisson = new SentinelRedisson("redis-master", sentinels, "123456");
RedissonClient redissonClient = sentinelRedisson.connect();
RAtomicLong atomicLong = redissonClient.getAtomicLong(TEST_KEY);
atomicLong.set(TEST_VALUE);
LOGGER.info("redisson哨兵模式:{}", redissonClient.getAtomicLong(TEST_KEY).get());
Assert.assertEquals(TEST_VALUE, redissonClient.getAtomicLong(TEST_KEY).get());
}
@Test
public void cluster() {
String[] redisNodes = new String[]{
"redis://192.168.56.81:6379",
"redis://192.168.56.82:6379",
"redis://192.168.56.83:6379",
"redis://192.168.56.84:6379",
"redis://192.168.56.85:6379",
"redis://192.168.56.86:6379"
};
ClusterRedisson clusterRedisson = new ClusterRedisson(redisNodes, "123456");
RedissonClient redissonClient = clusterRedisson.connect();
RAtomicLong atomicLong = redissonClient.getAtomicLong(TEST_KEY);
atomicLong.set(TEST_VALUE);
LOGGER.info("redisson集群模式:{}", redissonClient.getAtomicLong(TEST_KEY).get());
Assert.assertEquals(TEST_VALUE, redissonClient.getAtomicLong(TEST_KEY).get());
}
}
Redis高级客户端,线程安全的,单个Lettuce连接可以在多个线程中操作
基于Netty实现,使用非阻塞IO,支持异步
对Redis基础操作支持全面,相对Jedis来说更加高效,不要考虑太多线程安全问题
相对Redisson来说分布式锁和分布式数据结构等都需要自行实现
Spring现有版本的默认redis客户端
<dependency>
<groupId>io.lettucegroupId>
<artifactId>lettuce-coreartifactId>
<version>5.1.6.RELEASEversion>
dependency>
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
public class SingleInstanceLettuce {
private RedisURI redisURI;
/**
* 使用Lettuce连接单机单实例的redis
* @param host redis的主机地址
* @param port redis的端口号
* @param password redis的密码
*/
public SingleInstanceLettuce(String host, Integer port, String password) {
redisURI = RedisURI.builder()
.withHost(host)
.withPort(port)
.withPassword(password)
.build();
}
/**
* 连接redis获取一个连接
* @return 一个redis连接
*/
public StatefulRedisConnection<String, String> connect() {
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connect = redisClient.connect();
return connect;
}
}
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.codec.Utf8StringCodec;
import io.lettuce.core.masterslave.MasterSlave;
import io.lettuce.core.masterslave.StatefulRedisMasterSlaveConnection;
import java.util.List;
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
public class SentinelLettuce {
private List<RedisURI> redisURIList;
/**
* 连接哨兵模式的redis
* @param redisURIList 哨兵模式redis下的哨兵的信息,建议使用RedisURI.builder.sentinel填写哨兵信息来进行构造
*/
public SentinelLettuce(List<RedisURI> redisURIList) {
this.redisURIList = redisURIList;
}
/**
* 连接redis获取一个连接
* @return 一个redis的连接
*/
public StatefulRedisMasterSlaveConnection<String, String> connect() {
RedisClient redisClient = RedisClient.create();
StatefulRedisMasterSlaveConnection<String, String> connect = MasterSlave.connect(redisClient, new Utf8StringCodec(), redisURIList);
return connect;
}
}
import io.lettuce.core.RedisURI;
import io.lettuce.core.cluster.RedisClusterClient;
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
import java.util.List;
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
public class ClusterLettuce {
private List<RedisURI> redisURIList;
/**
* 使用Lettuce连接集群模式redis
* @param redisURIList 集群中redis节点的信息,建议使用RedisURI.builder来进行构造
*/
public ClusterLettuce(List<RedisURI> redisURIList) {
this.redisURIList = redisURIList;
}
/**
* 连接redis获取一个连接
* @return 一个redis的连接
*/
public StatefulRedisClusterConnection<String, String> connect() {
RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURIList);
StatefulRedisClusterConnection<String, String> connect = redisClusterClient.connect();
return connect;
}
}
以上三段代码是使用Lettuce连接三种模式下Redis的简易演示代码,下面再附上测试类代码
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
public class LettuceTest {
private static final Logger LOGGER = LoggerFactory.getLogger(LettuceTest.class);
private static final String TEST_KEY = "lettuce";
private static final String TEST_VALUE = "dream-hammer";
@Test
public void SingleInstance(){
SingleInstanceLettuce singleInstanceLettuce = new SingleInstanceLettuce("192.168.56.90", 6379, "123456");
StatefulRedisConnection<String, String> connection = singleInstanceLettuce.connect();
RedisCommands<String, String> commands = connection.sync();
commands.set(TEST_KEY, TEST_VALUE);
LOGGER.info("lettuce单机单实例:{}",commands.get(TEST_KEY));
Assert.assertEquals(TEST_VALUE,commands.get(TEST_KEY));
}
@Test
public void sentinel(){
List<RedisURI> redisURIList = new ArrayList<>();
redisURIList.add(RedisURI.builder().withSentinelMasterId("redis-master").withSentinel("192.168.56.91",26379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withSentinelMasterId("redis-master").withSentinel("192.168.56.92",26379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withSentinelMasterId("redis-master").withSentinel("192.168.56.93",26379).withPassword("123456").build());
SentinelLettuce sentinelLettuce = new SentinelLettuce(redisURIList);
StatefulRedisMasterSlaveConnection<String, String> connection = sentinelLettuce.connect();
RedisCommands<String, String> commands = connection.sync();
commands.set(TEST_KEY, TEST_VALUE);
LOGGER.info("lettuce哨兵模式:{}",commands.get(TEST_KEY));
Assert.assertEquals(TEST_VALUE,commands.get(TEST_KEY));
}
@Test
public void cluster(){
List<RedisURI> redisURIList = new ArrayList<>();
redisURIList.add(RedisURI.builder().withHost("192.168.56.81").withPort(6379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withHost("192.168.56.82").withPort(6379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withHost("192.168.56.83").withPort(6379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withHost("192.168.56.84").withPort(6379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withHost("192.168.56.85").withPort(6379).withPassword("123456").build());
redisURIList.add(RedisURI.builder().withHost("192.168.56.86").withPort(6379).withPassword("123456").build());
ClusterLettuce clusterLettuce = new ClusterLettuce(redisURIList);
StatefulRedisClusterConnection<String, String> connection = clusterLettuce.connect();
RedisAdvancedClusterCommands<String, String> commands = connection.sync();
commands.set(TEST_KEY, TEST_VALUE);
LOGGER.info("lettuce集群模式:{}",commands.get(TEST_KEY));
Assert.assertEquals(TEST_VALUE,commands.get(TEST_KEY));
}
}
二、在SpringBoot中使用Redis
在上一部分我们演示了直接使用不同的redis客户端连接Redis,并进行简单操作,在这一部分,我们将演示一下,在SpringBoot如何连接三种模式的redis
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
# 连接单机单实例版的redis配置
spring:
redis:
host: 192.168.56.90
port: 6379
password: 123456
database: 0
# 连接哨兵模式的redis配置
spring:
redis:
sentinel:
master: redis-master
nodes: 192.168.56.91:26379,192.168.56.92:26379,192.168.56.92:26379
password: 123456
# 连接集群模式redis配置
spring:
redis:
cluster:
nodes: 192.168.56.81:6379,192.168.56.82:6379,192.168.56.83:6379,192.168.56.84:6379,192.168.56.85:6379,192.168.56.86:6379
password: 123456
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
@Service("redisSpring")
public class RedisSpring {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
public Object redisTemplateOperate(Object key, Object value) {
redisTemplate.opsForValue().set(key, value);
return redisTemplate.opsForValue().get(key);
}
public String stringRedisTemplateOperate(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
return stringRedisTemplate.opsForValue().get(key);
}
}
/**
* @author 爱做梦的锤子
* @create 2020/7/20
*/
@SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
@EnableAutoConfiguration
public class SpringTest {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringTest.class);
@Autowired
private RedisSpring redisSpring;
private static final String TEST_KEY = "spring";
private static final String TEST_VALUE = "dream-hammer";
@Test
public void test() {
Object value = redisSpring.redisTemplateOperate(TEST_KEY, TEST_VALUE);
LOGGER.info("redisTemplate:{}",value);
Assert.assertEquals(value,TEST_VALUE);
String s = redisSpring.stringRedisTemplateOperate(TEST_KEY, TEST_VALUE);
LOGGER.info("stringRedisTemplate:{}",s);
Assert.assertEquals(TEST_VALUE,s);
}
}
在本篇中主要是代码演示,演示三种客户端连接三种模式下的redis的方式,可以帮助大家快速学习和使用redis。由于本篇代码比较多,所以代码锤子也传到了github地址为:https://github.com/telundusiji/dream-hammer/tree/master/module-6
个人公众号【爱做梦的锤子】,全网同id,个站 http://te-amo.site,欢迎关注,里面会分享更多有用知识
觉得不错就点个赞叭QAQ