springboot 整合 redis


视频链接
官网: https://redis.io/
中文官网: http://redis.cn/

文章地址
redis入门https://blog.csdn.net/qq_41538097/article/details/118097179
五大数据类型https://blog.csdn.net/qq_41538097/article/details/118123867
三种特殊数据类型https://blog.csdn.net/qq_41538097/article/details/118160898
Redis 事务,watch 监控(乐观锁)https://blog.csdn.net/qq_41538097/article/details/118198672
springboot 整合 redis https://blog.csdn.net/qq_41538097/article/details/118199634
RedisUtil 工具类https://blog.csdn.net/qq_41538097/article/details/118331927
Redis.conf 配置详解https://blog.csdn.net/qq_41538097/article/details/118334331
redis 持久化操作https://blog.csdn.net/qq_41538097/article/details/118340130
redis 发布订阅https://blog.csdn.net/qq_41538097/article/details/118348000
redis 主从复制https://blog.csdn.net/qq_41538097/article/details/118354527
redis 哨兵模式https://blog.csdn.net/qq_41538097/article/details/118360381
Ⅰ、jedis简单使用

java 操作 jedis ,jedis 是 redis 官方推荐的 java 连接开发工具!使用 Java 操作 redis 中间件

一、导入依赖

新建 maven 项目,导入 jedis 依赖

    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.6.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
    </dependencies>
  • 连接数据库
  • 操作命令
  • 断开连接
二、解决错误

如果遇到如下错误,查看我另一篇博客
https://blog.csdn.net/qq_41538097/article/details/118226758

Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. 
If you want to connect from external computers to Redis you may adopt one of the following solutions: 
1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 
2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 
3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 
4) Setup a bind address or an authentication password. 
NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
线程“main”中的异常 redis.clients.jedis.exceptions.JedisDataException:DENIED Redis 正在保护模式下运行,因为已启用保护模式,未指定绑定地址,未向客户端请求身份验证密码。在此模式下,仅接受来自环回接口的连接。
如果您想从外部计算机连接到 Redis,您可以采用以下解决方案之一:
1) 只需禁用保护模式,通过从与服务器相同的主机连接到 Redis,从环回接口发送命令“CONFIG SET protected-mode no”正在运行,但是如果这样做,请确保 Redis 不能从 Internet 公开访问。使用 CONFIG REWRITE 使此更改永久化。
2) 或者,您可以通过编辑 Redis 配置文件并将保护模式选项设置为“no”,然后重新启动服务器来禁用保护模式。 
3) 如果您手动启动服务器只是为了测试,请使用“--protected-mode no”选项重新启动它。 
4) 设置绑定地址或认证密码。
注意:您只需要执行上述操作之一,服务器就可以开始接受来自外部的连接。
三、使用 API 测试连接

java 测试 redis string 类型

 // 1、 new 一个 redis 对象
        Jedis jedis = new Jedis("1.117.165.107", 6378);
        jedis.auth("******");
        jedis.set("name", "tom");
        jedis.set("age", 18 + "");
        jedis.get("name"); // tom
        byte[] bytes = jedis.get(new byte[]{'a', 'g', 'e'});
        new String(bytes); // 18
        jedis.exists("name", "111"); // 1 返回的是一个 long 类型
        Set<String> keys = jedis.keys("*"); // [name, age]
        keys.toString();
        jedis.type("name"); // string
        jedis.randomKey(); // 随机返回一个 key
        jedis.rename("name", "username"); // 重命名 成功返回 OK,否则 报错
        jedis.get("username");
        jedis.del("age23"); // 删除 :返回 long 类型, 0
        jedis.select(2); // 切换数据库,返回 string 类型, OK --- 一共 16 个库 0~15,默认 0
        jedis.flushDB(); // 清空当前数据库,返回 string 类型, OK
        jedis.flushAll(); // 清空所有数据库

从上可以看出,使用方法和命令一摸一样,返回结果也相同,其他几种基本类型类似,可以直接参考命令使用

四、事务管理

和命令行类似

1、正常->事务
 Jedis jedis = new Jedis("1.117.165.107", 6378);
        jedis.auth("******");
        jedis.flushAll();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userName","sweet");
        jsonObject.put("age",18);
        Transaction multi = jedis.multi(); // 开启事务
        try {
            multi.set("user",jsonObject.toJSONString());
            multi.set("user2",jsonObject.toJSONString());
            multi.exec();   // 执行事务
        } catch (Exception e) {
            multi.discard(); // 放弃事务
            e.printStackTrace();
        } finally {
            System.out.println(jedis.get("user")); // 打印 {"userName":"sweet","age":18}
            System.out.println(jedis.get("user2")); // 打印 {"userName":"sweet","age":18}
            jedis.close();
        }
2、异常->事务
 Jedis jedis = new Jedis("1.117.165.107", 6378);
        jedis.auth("******");
        jedis.flushAll();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userName","sweet");
        jsonObject.put("age",18);
        Transaction multi = jedis.multi(); // 开启事务
        try {
            multi.set("user",jsonObject.toJSONString());
            multi.set("user2",jsonObject.toJSONString());
            System.out.println(1/0);
            multi.exec();   // 执行事务
        } catch (Exception e) {
            multi.discard(); // 放弃事务
            e.printStackTrace();
        } finally {
            System.out.println(jedis.get("user")); // 发生异常,打印 null 
            System.out.println(jedis.get("user2")); // 发生异常,打印 null 
            jedis.close();
        }
5、乐观锁

开启两个客户端利用延时操作测试

  • client 1
        Jedis jedis = new Jedis("1.117.165.107", 6378);
        jedis.auth("******");
        jedis.incrBy("age",10);
        System.out.println(jedis.get("age"));  // 28
  • client 2
      Jedis jedis = new Jedis("1.117.165.107", 6378);
        jedis.auth("******");
        jedis.set("age", "18");
        jedis.watch("age");
        Transaction multi = jedis.multi();
        Thread.sleep(20000);
        multi.decrBy("age", 20);
        multi.exec();
        System.out.println(jedis.get("age")); // 28

先运行 client2 ,再运行 client1,得到的结果都是 28(因为 client2 监听了年龄,在延时期间, client1 对其进行了修改,则二失败)

Ⅱ、springboot 整合
一、认识 spring-boot-starter-data-redis
  • springboot 操作数据:springboot jpa jdbc mongodb redis !
  • springdata 也是和 springboot 齐名,操作数据导包都是以 spring-boot-starter-data- 开始
  • 在这里插入图片描述

说明:在SpringBoot2.x之后,原来使用的jedis 被替换为了lettuce?

  • jedis :采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool连接池!更像BIO模式
  • lettuce :采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像NIO模式
二、配置 redis
1、源码分析

①、导入依赖

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

②、包说明

		<!--当前项目 依赖springboot 的 redis 包 spring-boot-starter-data-redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- spring-boot-starter-data-redis 包依赖了 spring-data-redis -->
            <dependency>
      <groupId>org.springframework.data</groupId>
	      <artifactId>spring-data-redis</artifactId>
	      <version>2.5.2</version>
	      <scope>compile</scope>
     </dependency>
     
       <!-- spring-data-redis 包依赖了 jedis -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>${jedis}</version>
			<optional>true</optional>
		</dependency>

③、redis 自动配置类 RedisAutoConfiguration
在这里插入图片描述
④、自动配置类绑定 properties 配置文件 RedisProperties

	private int database = 0;
	private String url;
	private String host = "localhost";
	private String username;
	private String password;
	private int port = 6379;
	private boolean ssl;
	private Duration timeout;
	private Duration connectTimeout;
	private String clientName;
	private ClientType clientType;
	private Sentinel sentinel;
	private Cluster cluster;

⑤、RedisAutoConfiguration 说明

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	// 默认的 RedisTemplate 没有过多的设置,redis 对象都是需要序列化的!
	// 两个泛型都是 Object 类型,后续使用需要强制类型转换
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	// string 是 最长使用的一个类类型,所以单独有一个 bean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
2、连接池配置

连接池配置 2.x 版本使用 lettuce
在这里插入图片描述
不确定支持哪个版本,可以查看RedisConnectionFactory
在这里插入图片描述
查看 RedisConnectionFactory 的实现类
在这里插入图片描述
发现 JedisConnectionFactory 有好多类找不到
在这里插入图片描述
查看 LettuceConnectionFactory 类正常
在这里插入图片描述
小结:

  • 综上所述, 2.x 版本默认使用 LettuceConnectionFactory (因为2.x以后,spring-boot-stater-data-redis 包中导入了 lettuce 包,没有导入jedis 客户端的包),如果需要使用 JedisConnectionFactory 需要导入 jedis.client

application.yml 配置
JedisConnectionFactory

spring:  
  redis:
    database: 0
    host: 1.117.165.107
    password: 111111
    port: 6378
    client-type: jedis # 客户端类型,主要为了这块导入的 jedis.client 包
    jedis:
      pool:
        max-active: 8   #最大连接数据库连接数,设 0 为没有限制
        max-idle: 8     #最大等待连接中的数量,设 0 为没有限制
        max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
        min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
    # url: redis://111111@111.111.111.111:6378 # url 配置和上面 host、password、port 相同,两种配置一种即可

导包

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

LettuceConnectionFactory------------可以使用

spring:  
  redis:
    database: 0
    host: 1.117.165.107
    password: 111111
    port: 6378
    client-type: lettuce
    lettuce:
      pool:
        max-active: 8   #最大连接数据库连接数,设 0 为没有限制
        max-idle: 8     #最大等待连接中的数量,设 0 为没有限制
        max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
        min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
    # url: redis://user:password@example.com:6379

可以配置指定不同数据库连接池

  @Autowired
  RedisConnectionFactory redisConnectionFactory;
  System.out.println(redisConnectionFactory.getClass());
 
 Lettuce 连接池
 class org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory
 Jredis 连接池
 class org.springframework.data.redis.connection.jedis.JedisConnectionFactory

注意: 要使用连接池必须有 commons-pool2 包,或者直接导入 jedis 包,该包中包含 commons-pool2包
导入 jedis 包
在这里插入图片描述
或者导入commons-pool2 包

 <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
</dependency>
  • 运行测试
`使用 redisTemplate 下面 api 可以对 redis 五大基本类型,三个特殊类型增查`
        // 操作字符串 string,其他类型类似
        redisTemplate.opsForValue().set("name","tom");
        redisTemplate.opsForValue().get("name");
        redisTemplate.opsForValue().increment("age",20);
        // 操作 list
        redisTemplate.opsForList();
        // 操作 set
        redisTemplate.opsForSet();
        // 操作 hash
        redisTemplate.opsForHash();
        // 操作 Geo 地理位置
        redisTemplate.opsForGeo();
        // 操作 HyperLogLog 基数统计
        redisTemplate.opsForHyperLogLog();
        // 操作有序集合 set
        redisTemplate.opsForZSet();
      
      `使用 redisTemplate 下面 api 可以对 redis 事务过期时间等做修改`
        redisTemplate.delete("user");
        redisTemplate.multi();
        redisTemplate.exec();
        redisTemplate.expire("", Duration.ofDays(1000*60));
        redisTemplate.expireAt("", Instant.ofEpochSecond(1000*60));
        redisTemplate.type("");
        redisTemplate.discard(); 

		`连接操作`
		RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.flushDb();
        connection.flushAll();
        connection.close();

三、序列化

值的序列化
在这里插入图片描述
默认使用 JDK 序列化
在这里插入图片描述

1、简单测试

存储对象

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private String userName;
    private int age;
}
    @Test
    void test(){
        User user = new User("法外狂徒", 18);
        redisTemplate.opsForValue().set("user",user);
        System.out.println(redisTemplate.opsForValue().get("user"));
    }
}

如果直接使用实体类进行序列化,存取正常,但是用客户端连接结果如下图,建议自定义实现 RedisTemplate,选择合适的序列化
在这里插入图片描述
存储对象必须 implements Serializable 将实体类进行实例化,否则会报错 ,默认使用 JDK 序列化
在这里插入图片描述

2、实现自己的 RedisTemplate

如下,可以看出序列化方式,默认为 JDK
在这里插入图片描述
RedisConfig 配置类,该文件必须与启动类同级或者下级
在这里插入图片描述
RedisConfig.java

@Configuration
public class RedisConfig {

    // 编写自己的  RedisTemplate
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        // 为了开发方便,将原来的泛型从 <Object, Object> 变为 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // JSON 序列化配置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // String 序列化配置
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key 采用 string 的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash 的 key 也采用 string 的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value 采用 JSON 序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash 的 value 采用 JSON 序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

3、测试

实体类不去实现序列化使用自己的 RedisTemplate 测试

    @Autowired
    @Qualifier("redisTemplate") // 实现 RedisTemplate 有好多,需要使用 @Qualifier 注解表明使用哪个 
    private RedisTemplate redisTemplate;
    @Test
    void test(){
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.flushAll();
        User user = new User("法外狂徒", 18);
        redisTemplate.opsForValue().set("user",user);
        redisTemplate.expireAt("user", new Date(System.currentTimeMillis() + 1000 * 60 * 60));
        System.out.println(redisTemplate.opsForValue().get("user"));
    }

测试结果
在这里插入图片描述

4、RedisUtil 工具类

工具类可以简化部分代码,每次都 redisTemplate.opsForValue() 挺麻烦,可以对其进行封装,参考

https://www.cnblogs.com/zhzhlong/p/11434284.html 博客实现自己的工具类
测试
RedisUtil.java

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;
    /**
     * 设置指定 key 的值
     * @param key
     * @param value
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }
     /**
     * 获取指定 key 的值
     * @param key
     * @return
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

SpringBootRedisApplicationTests.java

    @Autowired
    RedisUtil redisUtil;
    @Test
    void testRedisUtil(){
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.flushAll();
        User user = new User("法外狂徒", 18);
        redisUtil.set("user", user);
        redisUtil.expireAt("user", new Date(System.currentTimeMillis() + 1000 * 60 * 60));
        System.out.println(redisUtil.get("user"));
    }

运行结果
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值