SpringBoot集成Redis

发布于:2024-03-01 ⋅ 阅读:(51) ⋅ 点赞:(0)

1. 概述

默认有三种方式连接redis.

  • 第一种:jedis—传统的项目–ssm
  • 第二种:lettuce:---->刚出现没有多久就被springboot整合进来。
  • 第三种:springboot连接redis

2. 使用Jedis来连接redis

Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现了对各类API进行封装调用。

  • 引入jedis的jar包
  <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.3.1</version>
        </dependency>
  • 编写连接代码
public class JedisTest {
    public static void main(String[] args) {
        //1.或的Connection,通过ip和断开
        Jedis jedis=new Jedis("127.0.0.1",6379);
        //2.指定访问redis的密码(我的redis没有设置密码)
        //jedis.auth("111111");
        //3.测试连接是否成功
        System.out.println(jedis.ping());
    }
}

在这里插入图片描述

可以发现连接成功

  • 测试操作redis
public class JedisTest {
    public static void main(String[] args) {
        //1.或的Connection,通过ip和断开
        Jedis jedis=new Jedis("127.0.0.1",6379);
        //2.指定访问redis的密码(我的redis没有设置密码)
        //jedis.auth("111111");
        //3.测试连接是否成功
        System.out.println(jedis.ping());
        //4.操作redis
        jedis.set("k1","v1");
        jedis.set("k2","v2");
        Set<String> keys = jedis.keys("*");
        keys.forEach(System.out::println);
    }
}

在这里插入图片描述

3. 使用Lettuce来连接redis

Lettuce是一个Redis的Java驱动包。jedis和Lettuce都是Redis的客户端,它们都可以连接Redis服务器,但是在SpringBoot2.0之后默认使用的Lettuce这个客户端来连接Redis服务器,因为当使用Jedis客户端连接Redis服务器的时候,每个线程都要拿自己常见的Jedis实例取连接Redis客户端,当有很多个线程的时候,不仅开销大需要反复的创建关闭一个Jedis连接,而且线程也是不安全的,一个线程通过Jedis实例更改Redis服务器中的额数据之后会影响另一个线程。但是如果使用Lettuce这个客户端来连接Redis服务器的时候,就不会出现上面的问题,Lettuce底层使用的是Netty,当有多个线程都需要连接Redis服务器的时候,可以保证只创建一个Lettuce连接,使所有的线程都共享这一个Lettuce连接,这样可以减少创建关闭一个Lettuce连接时候的开销,而且这种方式也是线程安全的,不会出现一个线程通过Lettuce更改Redis服务器中的数据之后影响另一个线程的情况。

  • 导入依赖包
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
</dependency>
  • 测试代码
public class LettuceTest {
    public static void main(String[] args) {
        //1.使用构建器链式编程来builder我们的RedisURI
        RedisURI uri = RedisURI.builder().redis("127.0.0.1").withPort(6379).build() /*.withAUthentication("username","password")*/;
        //2.创建连接客户端
        RedisClient redisClient = RedisClient.create(uri);
        StatefulRedisConnection<String, String> connect = redisClient.connect();
        //3.创建操作的命令
        RedisCommands<String, String> commands = connect.sync();
        //String
        List<String> keys = commands.keys("*");
        keys.forEach(System.out::println);
        //string
        commands.set("k5","v5");
        System.out.println(commands.get("k5"));
        //4. 关闭释放资源
        connect.close();
    }
}

在这里插入图片描述

4. 使用Redis Template来连接Redis

  • 单机模式

导入pom

    <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

注意spring-boot-starter-data-redis默认就引入了lettuce,为了防止版本冲突,可以删除原先的版本

配置

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    #password: 
    lettuce:
      pool:
        max-active: 8
        max-wait: -1ms
        max-idle: 8
        min-idle: 0

创建redis的配置类

@Configuration
public class RedisConf {
//这里先不配置,测试一下待会的错误
}

创建Service接口

public interface OrderService {
    public void addOrder();
    public String getOrderById(String keys);
}
@Service
public class OrderServiceImpl implements OrderService {
    public static final String ORDER_KEY="ord:";
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void addOrder() {
        int kyeId= ThreadLocalRandom.current().nextInt(1000)+1;
        String serialNo= UUID.randomUUID().toString();
        String key=ORDER_KEY+kyeId;
        String value="京东订单"+serialNo;
        System.out.println(value);
        redisTemplate.opsForValue().set(key,value);
    }

    @Override
    public String getOrderById(String keys) {
        return (String) redisTemplate.opsForValue().get(keys);
    }
}

创建Controller

RestController
@Slf4j
public class OrderController {
    @Autowired
    private OrderService orderService;

    @RequestMapping(value = "/order/add",method = RequestMethod.POST)
    public void addOrder(){
        orderService.addOrder();
    }

     @RequestMapping(value = "/order/{keyId}",method = RequestMethod.GET)
    public void getOrder(@PathVariable String keyId){
        System.out.println(orderService.getOrderById("ord:"+keyId));
    }

}

访问添服务
首先redis数据库内容增加了:

在这里插入图片描述

可以发现是乱码

idea也有输出

在这里插入图片描述

出现乱码的原因归根到底是序列话的问题,Redis的键和值都是Spring提供的Serializer序列化到数据库的,RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerialzer,所以我们要使用StringRedisSerialzer来进行序列化。有一下解决方案
(1)使用StringRedisTemplate

@Service
public class OrderServiceImpl implements OrderService {
    public static final String ORDER_KEY="ord:";
//    @Autowired
//    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void addOrder() {
        int kyeId= ThreadLocalRandom.current().nextInt(1000)+1;
        String serialNo= UUID.randomUUID().toString();
        String key=ORDER_KEY+kyeId;
        String value="京东订单"+serialNo;
        System.out.println(value);
        stringRedisTemplate.opsForValue().set(key,value);
    }

    @Override
    public String getOrderById(String keys) {
        return stringRedisTemplate.opsForValue().get(keys);
    }
}

在这里插入图片描述

可以看到现在就正常了

在这里插入图片描述

查询服务也可以查到

(2)配置Redis配置类


@Configuration
public class RedisConf {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){
        RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return  redisTemplate;
    }

}

在这里插入图片描述

  • 集群模式

启动redis集群(集群搭建可以看上篇文章)
改写配置文件

spring:
	redis:
		cluster:
			max-redirects:3
			nodes: 192.168.111.175:6381, 192.168.111.175:6382, 192.168.111.172:6383, 192.168.111.172:6384,192.168.111.181:6385, 192.168.111.181:6386,
		lettuce:
      		pool:
       			max-active: 8
       			max-wait: -1ms
       			max-idle: 8
       			min-idle: 0
		

通过微服务访问redis集群
访问方式和单机模式一样的,集群对客户是透明的。

常见问题
SpringBoot客户端没有动态感知到RedisCluster的最新集群信息例如,Redis Cluster集群部署采用的3主3从拓补结构,数据读写访问master节点,slave节点负责备份,当master宕机后主从切换成功,redis手动ok,但是存在两个经典bug:
在这里插入图片描述
出现上面故障的原因是,SpringBoot2.x版本,redis默认使用的连接池是Lettuce,当redis集群节点发生变化后,Lettuce默认是不会刷新节点拓补结构的。

上面问题的解决方案方案是:

  1. 排除lettuce采用jedis(不推荐)

在这里插入图片描述
2. 重写连接工程实例(改源码,极度不推荐)
3. 刷新节点集群的拓补结构感应(推荐)

spring:
	redis:
		cluster:
			max-redirects:3
			nodes: 192.168.111.175:6381, 192.168.111.175:6382, 192.168.111.172:6383, 192.168.111.172:6384,192.168.111.181:6385, 192.168.111.181:6386,
		lettuce:
		    cluster:
		    #这个是默认关闭的,这里设置为2s刷新
		    	refresh:
		    		adaptive: true;
		    		period: 2000
      		pool:
       			max-active: 8
       			max-wait: -1ms
       			max-idle: 8
       			min-idle: 0
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到