一起学习Redis之在Java中使用

Posted 爱做梦的锤子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一起学习Redis之在Java中使用相关的知识,希望对你有一定的参考价值。

操作系统:CentOS-7.8  
Redis版本:6.0.5  
SpringBoot 2.1.5.RELEASE  
Java Version 1.8.0_231

一、使用Redis客户端

Jedis、Redisson和Lettuce都是比较常用的支持连接Redis的客户端,所以在这里我们主要演示这三种客户端如何连接不同的redis模式的redis

1.Jedis

Jedis特点

  • 比较经典的Redis的Java客户端,对Redis的命令支持比较全面

  • 比较轻量和简洁,对其进行改造和集成比较方便

  • 不支持异步,方法调用都是同步的,使用的阻塞IO

  • 客户端实例非线程安全,多线程并发场景下,需要通过连接池来使用客户端

  • 早期版本Spring的默认客户端

使用演示

  • pom依赖

1<dependency>
2    <groupId>redis.clients</groupId>
3    <artifactId>jedis</artifactId>
4    <version>2.9.3</version>
5</dependency>
  • Jedis连接单机单实例Redis

 1import redis.clients.jedis.Jedis;
2
3/**
4 * @author 爱做梦的锤子
5 * @create 2020/7/17
6 */

7public class SingleInstanceJedis {
8
9
10    private String host;
11    private Integer port;
12    private String password;
13
14    /**
15     * 连接单机单实例的redis
16     *
17     * @param host     redis主机地址
18     * @param port     redis服务端口
19     * @param password redis认证密码
20     */

21    public SingleInstanceJedis(String host, Integer port, String password) {
22        this.host = host;
23        this.port = port;
24        this.password = password;
25    }
26
27    /**
28     * 连接redis
29     *
30     * @return 一个Jedis客户端
31     */

32    public Jedis connect() {
33        Jedis jedis = new Jedis(host, port);
34        jedis.auth(password);
35        return jedis;
36    }
37
38}
  • Jedis连接哨兵模式Redis

 1import redis.clients.jedis.Jedis;
2import redis.clients.jedis.JedisPoolConfig;
3import redis.clients.jedis.JedisSentinelPool;
4
5import java.util.Set;
6
7/**
8 * @author 爱做梦的锤子
9 * @create 2020/7/17
10 */

11public class SentinelJedis {
12
13    private JedisSentinelPool jedisSentinelPool;
14
15    /**
16     * 连接哨兵模式的redis
17     *
18     * @param masterName redis的master名称
19     * @param sentinels  哨兵的主机和端口信息
20     * @param password   redis的认证密码
21     */

22    public SentinelJedis(String masterName, Set<String> sentinels, String password) {
23        //根据redis的信息创建一个redis哨兵的连接池
24        JedisPoolConfig config = new JedisPoolConfig();
25        config.setMaxTotal(10);
26        config.setMaxIdle(5);
27        config.setMinIdle(5);
28        jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, config, password);
29    }
30
31    /**
32     * 从连接池中取出一个客户端
33     *
34     * @return 获取一个Jedis客户端
35     */

36    public Jedis connect() {
37        return jedisSentinelPool.getResource();
38    }
39
40    /**
41     * 销毁连接池
42     */

43    public void close() {
44        jedisSentinelPool.close();
45        jedisSentinelPool.destroy();
46    }
47}
  • Jedis连接集群模式Redis

 1import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
2import redis.clients.jedis.HostAndPort;
3import redis.clients.jedis.JedisCluster;
4
5import java.util.Set;
6
7/**
8 * @author 爱做梦的锤子
9 * @create 2020/7/17
10 */

11public class ClusterJedis {
12
13    private Set<HostAndPort> redisNodes;
14    private String password;
15    private GenericObjectPoolConfig config;
16
17    /**
18     * 连接redis cluster
19     *
20     * @param redisNodes 集群中redis节点信息
21     * @param password   redis 密码
22     */

23    public ClusterJedis(Set<HostAndPort> redisNodes, String password) {
24        this.redisNodes = redisNodes;
25        this.password = password;
26        config = new GenericObjectPoolConfig();
27        config.setMaxTotal(10);
28        config.setMaxIdle(5);
29        config.setMinIdle(5);
30    }
31
32    /**
33     * 连接redis cluster
34     *
35     * @return 一个redis cluster客户端
36     */

37    public JedisCluster connect() {
38        JedisCluster jedisCluster = new JedisCluster(redisNodes, 10000100003, password, config);
39        return jedisCluster;
40    }
41
42}

以上三段代码是使用Jedis连接三种模式下Redis的简易演示代码,下面再附上测试类代码

  • 测试类

 1/**
2 * @author 爱做梦的锤子
3 * @create 2020/7/17
4 */

5
6public class JedisTest {
7
8    private static final Logger LOGGER = LoggerFactory.getLogger(JedisTest.class);
9    private static final String TEST_KEY = "jedis";
10    private static final String TEST_VALUE = "dream-hammer";
11
12    @Test
13    public void singleInstance() {
14        SingleInstanceJedis singleInstanceJedis = new SingleInstanceJedis("192.168.56.90"6379"123456");
15        Jedis jedis = singleInstanceJedis.connect();
16        jedis.set(TEST_KEY, TEST_VALUE);
17        LOGGER.info("jedis单机单实例:{}", jedis.get(TEST_KEY));
18        Assert.assertEquals(TEST_VALUE, jedis.get(TEST_KEY));
19    }
20
21    @Test
22    public void sentinel() {
23        Set<String> sentinels = new HashSet<>();
24        sentinels.add("192.168.56.91:26379");
25        sentinels.add("192.168.56.92:26379");
26        sentinels.add("192.168.56.93:26379");
27        SentinelJedis sentinelJedis = new SentinelJedis("redis-master", sentinels, "123456");
28        Jedis jedis = sentinelJedis.connect();
29        jedis.set(TEST_KEY, TEST_VALUE);
30        LOGGER.info("jedis哨兵模式:{}", jedis.get(TEST_KEY));
31        Assert.assertEquals(TEST_VALUE, jedis.get(TEST_KEY));
32    }
33
34    @Test
35    public void cluster() {
36        Set<HostAndPort> redisNodes = new HashSet<>();
37        redisNodes.add(new HostAndPort("192.168.56.81",6379));
38        redisNodes.add(new HostAndPort("192.168.56.82",6379));
39        redisNodes.add(new HostAndPort("192.168.56.83",6379));
40        redisNodes.add(new HostAndPort("192.168.56.84",6379));
41        redisNodes.add(new HostAndPort("192.168.56.85",6379));
42        redisNodes.add(new HostAndPort("192.168.56.86",6379));
43        ClusterJedis clusterJedis = new ClusterJedis(redisNodes, "123456");
44        JedisCluster jedisCluster = clusterJedis.connect();
45        jedisCluster.set(TEST_KEY, TEST_VALUE);
46        LOGGER.info("jedis集群模式:{}", jedisCluster.get(TEST_KEY));
47        Assert.assertEquals(TEST_VALUE, jedisCluster.get(TEST_KEY));
48    }
49}

2.Redisson

Redisson特点

  • 基于Netty实现,使用非阻塞IO,支持异步,性能高

  • API是线程安全的,可以操作单个Redisson连接来完成多种操作

  • 实现多种分布式和可扩展的Java数据结构,例如,分布式锁,分布式集合,可通过Redis支持延迟队列

  • Redisson注重分布式和锁的相关功能,所以在基础功能上较为简单,不支持Redis的原生命令操作,比如不支持字符串操作等

使用演示

  • pom依赖

1<dependency>
2    <groupId>org.redisson</groupId>
3    <artifactId>redisson</artifactId>
4    <version>3.12.5</version>
5</dependency>
  • redisson连接单机单实例Redis

 1import org.redisson.Redisson;
2import org.redisson.api.RedissonClient;
3import org.redisson.config.Config;
4
5/**
6 * @author 爱做梦的锤子
7 * @create 2020/7/17
8 */

9public class SingleInstanceRedisson {
10
11    private Config config;
12
13    /**
14     * 连接单机单实例的redis
15     *
16     * @param host     redis主机地址
17     * @param port     redis 端口
18     * @param password redis密码
19     */

20    public SingleInstanceRedisson(String host, Integer port, String password) {
21        config = new Config();
22        config.useSingleServer()
23                .setAddress("redis://" + host + ":" + port)
24                .setPassword(password);
25
26    }
27
28    /**
29     * 连接redis
30     *
31     * @return 一个RedissonClient客户端
32     */

33    public RedissonClient connect() {
34        RedissonClient redissonClient = Redisson.create(config);
35        return redissonClient;
36    }
37}
  • redisson连接哨兵模式Redis

 1import org.redisson.Redisson;
2import org.redisson.api.RedissonClient;
3import org.redisson.config.Config;
4
5/**
6 * @author 爱做梦的锤子
7 * @create 2020/7/17
8 */

9public class SentinelRedisson {
10
11    private Config config;
12
13    /**
14     * 连接哨兵模式redis
15     *
16     * @param masterName redis的master名称
17     * @param sentinels  哨兵的连接信息 redis://sentinelHost:sentinelPort
18     * @param password   redis密码
19     */

20    public SentinelRedisson(String masterName, String[] sentinels, String password) {
21        config = new Config();
22        config.useSentinelServers()
23                .setMasterName(masterName)
24                .addSentinelAddress(sentinels)
25                .setPassword(password);
26
27    }
28
29    /**
30     * 连接redis
31     *
32     * @return 一个RedissonClient客户端
33     */

34    public RedissonClient connect() {
35        RedissonClient redissonClient = Redisson.create(config);
36        return redissonClient;
37    }
38
39}
  • redisson连接集群模式Redis

 1import org.redisson.Redisson;
2import org.redisson.api.RedissonClient;
3import org.redisson.config.Config;
4
5/**
6 * @author 爱做梦的锤子
7 * @create 2020/7/17
8 */

9public class ClusterRedisson {
10
11    private Config config;
12
13    /**
14     * 连接cluster模式的redis
15     *
16     * @param redisNodes redis集群中节点信息 redis://nodeHost:nodePort
17     * @param password   redis密码
18     */

19    public ClusterRedisson(String[] redisNodes, String password) {
20        config = new Config();
21        config.useClusterServers()
22                .addNodeAddress(redisNodes)
23                .setPassword(password);
24
25    }
26
27    /**
28     * 连接redis
29     *
30     * @return 一个RedissonClient客户端
31     */

32    public RedissonClient connect() {
33        RedissonClient redissonClient = Redisson.create(config);
34        return redissonClient;
35    }
36
37}

以上三段代码是使用Redisson连接三种模式下Redis的简易演示代码,下面再附上测试类代码

  • 测试类

 1/**
2 * @author 爱做梦的锤子
3 * @create 2020/7/20
4 */

5public class RedissonTest {
6
7    private static final Logger LOGGER = LoggerFactory.getLogger(RedissonTest.class);
8    private static final String TEST_KEY = "redisson";
9    private static final long TEST_VALUE = 100L;
10
11    @Test
12    public void singleInstance() {
13        SingleInstanceRedisson singleInstanceRedisson = new SingleInstanceRedisson("192.168.56.90"6379"123456");
14        RedissonClient redissonClient = singleInstanceRedisson.connect();
15        RAtomicLong atomicLong = redissonClient.getAtomicLong(TEST_KEY);
16        atomicLong.set(TEST_VALUE);
17        LOGGER.info("redisson单机单实例:{}", redissonClient.getAtomicLong(TEST_KEY).get());
18        Assert.assertEquals(TEST_VALUE, redissonClient.getAtomicLong(TEST_KEY).get());
19    }
20
21    @Test
22    public void sentinel() {
23        String[] sentinels = new String[]{"redis://192.168.56.91:26379""redis://192.168.56.92:26379""redis://192.168.56.93:26379"};
24        SentinelRedisson sentinelRedisson = new SentinelRedisson("redis-master", sentinels, "123456");
25        RedissonClient redissonClient = sentinelRedisson.connect();
26        RAtomicLong atomicLong = redissonClient.getAtomicLong(TEST_KEY);
27        atomicLong.set(TEST_VALUE);
28        LOGGER.info("redisson哨兵模式:{}", redissonClient.getAtomicLong(TEST_KEY).get());
29        Assert.assertEquals(TEST_VALUE, redissonClient.getAtomicLong(TEST_KEY).get());
30    }
31
32    @Test
33    public void cluster() {
34        String[] redisNodes = new String[]{
35                "redis://192.168.56.81:6379",
36                "redis://192.168.56.82:6379",
37                "redis://192.168.56.83:6379",
38                "redis://192.168.56.84:6379",
39                "redis://192.168.56.85:6379",
40                "redis://192.168.56.86:6379"
41        };
42        ClusterRedisson clusterRedisson = new ClusterRedisson(redisNodes, "123456");
43        RedissonClient redissonClient = clusterRedisson.connect();
44        RAtomicLong atomicLong = redissonClient.getAtomicLong(TEST_KEY);
45        atomicLong.set(TEST_VALUE);
46        LOGGER.info("redisson集群模式:{}", redissonClient.getAtomicLong(TEST_KEY).get());
47        Assert.assertEquals(TEST_VALUE, redissonClient.getAtomicLong(TEST_KEY).get());
48    }
49}

3.Lettuce

Lettuce特点

  • Redis高级客户端,线程安全的,单个Lettuce连接可以在多个线程中操作

  • 基于Netty实现,使用非阻塞IO,支持异步

  • 对Redis基础操作支持全面,相对Jedis来说更加高效,不要考虑太多线程安全问题

  • 相对Redisson来说分布式锁和分布式数据结构等都需要自行实现

  • Spring现有版本的默认redis客户端

使用演示

  • pom依赖

1<dependency>
2    <groupId>io.lettuce</groupId>
3    <artifactId>lettuce-core</artifactId>
4    <version>5.1.6.RELEASE</version>
5</dependency>
  • lettuce连接单机单实例Redis

 1import io.lettuce.core.RedisClient;
2import io.lettuce.core.RedisURI;
3import io.lettuce.core.api.StatefulRedisConnection;
4
5/**
6 * @author 爱做梦的锤子
7 * @create 2020/7/20
8 */

9public class SingleInstanceLettuce {
10
11    private RedisURI redisURI;
12
13    /**
14     * 使用Lettuce连接单机单实例的redis
15     * @param host redis的主机地址
16     * @param port redis的端口号
17     * @param password redis的密码
18     */

19    public SingleInstanceLettuce(String host, Integer port, String password) {
20        redisURI = RedisURI.builder()
21                .withHost(host)
22                .withPort(port)
23                .withPassword(password)
24                .build();
25    }
26
27    /**
28     * 连接redis获取一个连接
29     * @return 一个redis连接
30     */

31    public StatefulRedisConnection<String, String> connect() {
32        RedisClient redisClient = RedisClient.create(redisURI);
33        StatefulRedisConnection<String, String> connect = redisClient.connect();
34        return connect;
35    }
36}
  • lettuce连接哨兵模式redis

 1import io.lettuce.core.RedisClient;
2import io.lettuce.core.RedisURI;
3import io.lettuce.core.codec.Utf8StringCodec;
4import io.lettuce.core.masterslave.MasterSlave;
5import io.lettuce.core.masterslave.StatefulRedisMasterSlaveConnection;
6
7import java.util.List;
8
9/**
10 * @author 爱做梦的锤子
11 * @create 2020/7/20
12 */

13public class SentinelLettuce {
14    private List<RedisURI> redisURIList;
15
16    /**
17     * 连接哨兵模式的redis
18     * @param redisURIList 哨兵模式redis下的哨兵的信息,建议使用RedisURI.builder.sentinel填写哨兵信息来进行构造
19     */

20    public SentinelLettuce(List<RedisURI> redisURIList) {
21        this.redisURIList = redisURIList;
22    }
23
24    /**
25     * 连接redis获取一个连接
26     * @return 一个redis的连接
27     */

28    public StatefulRedisMasterSlaveConnection<String, String> connect() {
29        RedisClient redisClient = RedisClient.create();
30        StatefulRedisMasterSlaveConnection<String, String> connect = MasterSlave.connect(redisClient, new Utf8StringCodec(), redisURIList);
31        return connect;
32    }
33}
  • lettuce连接集群模式Redis

 1import io.lettuce.core.RedisURI;
2import io.lettuce.core.cluster.RedisClusterClient;
3import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
4
5import java.util.List;
6
7/**
8 * @author 爱做梦的锤子
9 * @create 2020/7/20
10 */

11public class ClusterLettuce {
12
13    private List<RedisURI> redisURIList;
14
15    /**
16     * 使用Lettuce连接集群模式redis
17     * @param redisURIList 集群中redis节点的信息,建议使用RedisURI.builder来进行构造
18     */

19    public ClusterLettuce(List<RedisURI> redisURIList) {
20        this.redisURIList = redisURIList;
21    }
22
23    /**
24     * 连接redis获取一个连接
25     * @return 一个redis的连接
26     */

27    public StatefulRedisClusterConnection<String, String> connect() {
28        RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURIList);
29        StatefulRedisClusterConnection<String, String> connect = redisClusterClient.connect();
30        return connect;
31    }
32
33
34}

以上三段代码是使用Lettuce连接三种模式下Redis的简易演示代码,下面再附上测试类代码

  • 测试类

 1/**
2 * @author 爱做梦的锤子
3 * @create 2020/7/20
4 */

5public class LettuceTest {
6
7    private static final Logger LOGGER = LoggerFactory.getLogger(LettuceTest.class);
8    private static final String TEST_KEY = "lettuce";
9    private static final String TEST_VALUE = "dream-hammer";
10
11    @Test
12    public void SingleInstance(){
13        SingleInstanceLettuce singleInstanceLettuce = new SingleInstanceLettuce("192.168.56.90"6379"123456");
14        StatefulRedisConnection<String, String> connection = singleInstanceLettuce.connect();
15        RedisCommands<String, String> commands = connection.sync();
16        commands.set(TEST_KEY, TEST_VALUE);
17        LOGGER.info("lettuce单机单实例:{}",commands.get(TEST_KEY));
18        Assert.assertEquals(TEST_VALUE,commands.get(TEST_KEY));
19    }
20
21    @Test
22    public void sentinel(){
23        List<RedisURI> redisURIList = new ArrayList<>();
24        redisURIList.add(RedisURI.builder().withSentinelMasterId("redis-master").withSentinel("192.168.56.91",26379).withPassword("123456").build());
25        redisURIList.add(RedisURI.builder().withSentinelMasterId("redis-master").withSentinel("192.168.56.92",26379).withPassword("123456").build());
26        redisURIList.add(RedisURI.builder().withSentinelMasterId("redis-master").withSentinel("192.168.56.93",26379).withPassword("123456").build());
27        SentinelLettuce sentinelLettuce = new SentinelLettuce(redisURIList);
28        StatefulRedisMasterSlaveConnection<String, String> connection = sentinelLettuce.connect();
29        RedisCommands<String, String> commands = connection.sync();
30        commands.set(TEST_KEY, TEST_VALUE);
31        LOGGER.info("lettuce哨兵模式:{}",commands.get(TEST_KEY));
32        Assert.assertEquals(TEST_VALUE,commands.get(TEST_KEY));
33    }
34
35    @Test
36    public void cluster(){
37        List<RedisURI> redisURIList = new ArrayList<>();
38        redisURIList.add(RedisURI.builder().withHost("192.168.56.81").withPort(6379).withPassword("123456").build());
39        redisURIList.add(RedisURI.builder().withHost("192.168.56.82").withPort(6379).withPassword("123456").build());
40        redisURIList.add(RedisURI.builder().withHost("192.168.56.83").withPort(6379).withPassword("123456").build());
41        redisURIList.add(RedisURI.builder().withHost("192.168.56.84").withPort(6379).withPassword("123456").build());
42        redisURIList.add(RedisURI.builder().withHost("192.168.56.85").withPort(6379).withPassword("123456").build());
43        redisURIList.add(RedisURI.builder().withHost("192.168.56.86").withPort(6379).withPassword("123456").build());
44        ClusterLettuce clusterLettuce = new ClusterLettuce(redisURIList);
45        StatefulRedisClusterConnection<String, String> connection = clusterLettuce.connect();
46        RedisAdvancedClusterCommands<String, String> commands = connection.sync();
47        commands.set(TEST_KEY, TEST_VALUE);
48        LOGGER.info("lettuce集群模式:{}",commands.get(TEST_KEY));
49        Assert.assertEquals(TEST_VALUE,commands.get(TEST_KEY));
50    }
51
52}

二、在SpringBoot中使用Redis

在上一部分我们演示了直接使用不同的redis客户端连接Redis,并进行简单操作,在这一部分,我们将演示一下,在SpringBoot如何连接三种模式的redis

  • pom依赖

1<dependency>
2    <groupId>org.springframework.boot</groupId>
3    <artifactId>spring-boot-starter-data-redis</artifactId>
4</dependency>
  • 在application.yml文件中配置redis连接信息

 1# 连接单机单实例版的redis配置
2spring:
3  redis:
4    host: 192.168.56.90
5    port: 6379
6    password: 123456
7    database: 0
8
9# 连接哨兵模式的redis配置
10spring:
11  redis:
12    sentinel:
13      master: redis-master
14      nodes: 192.168.56.91:26379,192.168.56.92:26379,192.168.56.92:26379
15    password: 123456
16
17# 连接集群模式redis配置
18spring:
19  redis:
20    cluster:
21      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
22    password: 123456
  • 使用演示代码

 1/**
2 * @author 爱做梦的锤子
3 * @create 2020/7/20
4 */

5@Service("redisSpring")
6public class RedisSpring {
7
8    @Autowired
9    private RedisTemplate redisTemplate;
10
11    @Autowired
12    private StringRedisTemplate stringRedisTemplate;
13
14    public Object redisTemplateOperate(Object key, Object value) {
15        redisTemplate.opsForValue().set(key, value);
16        return redisTemplate.opsForValue().get(key);
17    }
18
19    public String stringRedisTemplateOperate(String key, String value) {
20        stringRedisTemplate.opsForValue().set(key, value);
21        return stringRedisTemplate.opsForValue().get(key);
22    }
23
24}
  • 测试该功能的代码

 1/**
2 * @author 爱做梦的锤子
3 * @create 2020/7/20
4 */

5@SpringBootTest(classes = Application.class)
6@RunWith(SpringRunner.class)
7@EnableAutoConfiguration
8public class SpringTest {
9
10    private static final Logger LOGGER = LoggerFactory.getLogger(SpringTest.class);
11
12    @Autowired
13    private RedisSpring redisSpring;
14
15    private static final String TEST_KEY = "spring";
16    private static final String TEST_VALUE = "dream-hammer";
17
18    @Test
19    public void test() {
20        Object value = redisSpring.redisTemplateOperate(TEST_KEY, TEST_VALUE);
21        LOGGER.info("redisTemplate:{}",value);
22        Assert.assertEquals(value,TEST_VALUE);
23        String s = redisSpring.stringRedisTemplateOperate(TEST_KEY, TEST_VALUE);
24        LOGGER.info("stringRedisTemplate:{}",s);
25        Assert.assertEquals(TEST_VALUE,s);
26    }
27
28}

总结

觉得不错就点个赞叭QAQ


以上是关于一起学习Redis之在Java中使用的主要内容,如果未能解决你的问题,请参考以下文章

Redis之在Linux上安装和简单的使用

redis之在windows10下redis的安装配置启动

洛谷 P1184高手之在一起 题解

题解 P1184 高手之在一起

142Java内部类之在普通方法里面定义内部类

Java面试题之在多线程情况下,单例模式中懒汉和饿汉会有什么问题呢?