Redis篇(Java操作Redis)

news2024/11/16 23:42:19

目录

讲解一:简介

讲解二:Jedis

Github

一、创建项目、

二、添加依赖

三、配置文件

四、Java连接Redis

五、通过Redis连接池获取连接对象并操作服务器

六、封装JedisUtil对外提供连接对象获取方法

七、Java操作Redis五种数据类型

1. 连接与释放

2. Jedis操作string数据类型

3. Jedis操作hash类型

4. Jedis操作list类型

5. Jedis操作set类型

6. Jedis操作sortedset数据类型

八、层级目录+失效时间

九、获取所有key&事务&删除

十、Jedis操作byte数组

讲解三:SpringDataRedis

一、简介

二、创建项目

三、添加依赖

四、添加application.yml配置文件

五、Lettuce和Jedis的区别

六、测试环境测试环境是否搭建成功

七、SpringDataRedis序列化模板

1. 序列化问题

2. 序列化解决方案

3. 自定义序列化

4. StringRedisTemplate

八、SpringData操作Redis

1. 操作string数据类型

2. 操作hash数据类型

3. 操作list数据类型

4. 操作set数据类型

5. 操作sortedset数据类型

6. 获取所有key+设置key失效时间

获取所有key&删除

设置key的失效时间

7. 通用操作

九、SpringDataRedis整合哨兵

application.yml

Bean注解配置

十、知识小结


讲解一:简介

在Redis官网中提供了各种语言的客户端,

官网地址:Connect with Redis clients | Docs

操作Redis 的 Java 客户端很多,官方推荐的有三种:

  • Jedis
  • Lettuce
  • Redisson

标记为的就是推荐使用的java客户端,包括:

  • Jedis和Lettuce:这两个主要是提供了Redis命令对应的API,方便我们操作Redis,而Spring 对 Redis 客户

端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-

boot-starter-data-redis。

  • Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如:Map、Queue等,而且支持跨

进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。

讲解二:Jedis

Github

Jedis 是 Redis 的 Java 版本的客户端实现。

Jedis的官网地址: https://github.com/redis/jedis

一、创建项目、

自己创建一个Maven项目

二、添加依赖

<?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.4.RELEASE</version>

        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.xxxx</groupId>

    <artifactId>redis-demo</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <name>redis-demo</name>

    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>

    </properties>

    <dependencies>
        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-data-redis</artifactId>

            <!--
                1.x 的版本默认采用的连接池技术是 Jedis,
                2.0 以上版本默认连接池是 Lettuce,
                如果采用 Jedis,需要排除 Lettuce 的依赖。
             -->
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>

                    <artifactId>lettuce-core</artifactId>

                </exclusion>

            </exclusions>

        </dependency>

        <!-- jedis 依赖 -->
        <dependency>
            <groupId>redis.clients</groupId>

            <artifactId>jedis</artifactId>

        </dependency>

        <!--web组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <!--test 组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

    </dependencies>

</project>

三、配置文件

spring:
  redis:
    # Redis服务器地址
    host: 192.168.10.100
    # Redis服务器端口
    port: 6379
    # Redis服务器密码
    password: root
    # 选择哪个库,默认0库
    database: 0
    # 连接超时时间
    timeout: 10000ms
    jedis:
      pool:
        # 最大连接数,默认8
        max-active: 1024
        # 最大连接阻塞等待时间,单位毫秒,默认-1ms
        max-wait: 10000ms
        # 最大空闲连接,默认8
        max-idle: 200
        # 最小空闲连接,默认0
        min-idle: 5

四、Java连接Redis

/**
 * 连接Redis
 */
@Test
public void initConn01() {
    // 创建jedis对象,连接redis服务
    Jedis jedis = new Jedis("192.168.10.100", 6379);
    
    // 设置认证密码
    jedis.auth("root");
    
    // 指定数据库 默认是0
    jedis.select(1);
    
    // 使用ping命令,测试连接是否成功
    String result = jedis.ping();
    System.out.println(result);// 返回PONG
    
    // 添加一条数据
    jedis.set("username", "zhangsan");
    
    // 获取一条数据
    String username = jedis.get("username");
    System.out.println(username);
    
    // 释放资源
    if (jedis != null)
        jedis.close();
}

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,

因此我们推荐大家使用Jedis连接池代替Jedis的直连方式

package com.project.jedis.util;

import redis.clients.jedis.*;

public class JedisConnectionFactory {

    private static JedisPool jedisPool;

    static {
        // 配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(8);
        poolConfig.setMaxIdle(8);
        poolConfig.setMinIdle(0);
        poolConfig.setMaxWaitMillis(1000);
        // 创建连接池对象,参数:连接池配置、服务端ip、服务端端口、超时时间、密码
        jedisPool = new JedisPool(poolConfig, "192.168.150.101", 6379, 1000, "123321");
    }

    public static Jedis getJedis(){
        return jedisPool.getResource();
    }
}

五、通过Redis连接池获取连接对象并操作服务器

/**
 * 通过Redis连接池获取连接对象
 */
@Test
public void initConn02() {
    // 初始化redis客户端连接池
    JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "192.168.10.100", 6379, 10000, "root");
    
    // 从连接池获取连接
    Jedis jedis = jedisPool.getResource();
    
    // 指定数据库 默认是0
    jedis.select(2);
    
    // 使用ping命令,测试连接是否成功
    String result = jedis.ping();
    System.out.println(result);// 返回PONG

    // 添加一条数据
    jedis.set("username", "zhangsan");
    
    // 获取一条数据
    String username = jedis.get("username");
    System.out.println(username);
    
    // 释放资源
    if (jedis != null)
        jedis.close();
}

六、封装JedisUtil对外提供连接对象获取方法

@Configuration
public class RedisConfig {

    //服务器地址
    @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 String timeout;
    
    //最大连接数
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxTotal;
    
    //最大连接阻塞等待时间
    @Value("${spring.redis.jedis.pool.max-wait}")
    private String maxWaitMillis;
    
    //最大空闲连接
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    
    //最小空闲连接
    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;
    
    @Bean
    public JedisPool redisPoolFactory(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //注意值的转变
  		jedisPoolConfig.setMaxWaitMillis
  		(Long.parseLong(maxWaitMillis.substring(0,maxWaitMillis.length()-2)));
        //注意属性名
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, 

        Integer.parseInt(timeout.substring(0,timeout.length() - 2)), password);
        
        return jedisPool;
   }
}

七、Java操作Redis五种数据类型

1. 连接与释放

@Autowired
private JedisPool jedisPool;

private Jedis jedis = null;

//初始化jedis对象实例
@Before
public void initConn(){
    jedis = jedisPool.getResource();
}

//释放资源
@After
public void closeConn(){
    if (jedis!=null){
        jedis.close();
   }
}

2. Jedis操作string数据类型

// 1.操作String
@Test
public void testString() {
   // 添加一条数据
   jedis.set("username", "zhangsan");
   jedis.set("age", "18");
   
   // 添加多条数据 参数奇数为key 参数偶数为value
   jedis.mset("address", "bj", "sex", "1");
   
   // 获取一条数据
   String username = jedis.get("username");
   System.out.println(username);
   
   // 获取多条数据
   List<String> list = jedis.mget("username", "age", "address", "sex");
   for (String str : list) {
      System.out.println(str);
   }
   
   // 删除
   //jedis.del("username");

}

3. Jedis操作hash类型

// 2.操作Hash
@Test
public void testHash() {
   /*
    * 添加一条数据
    *     参数一:redis的key
    *     参数二:hash的key
    *     参数三:hash的value
    */
   jedis.hset("userInfo", "name", "lisi");
   
   // 添加多条数据
   Map<String, String> map = new HashMap<>();
   map.put("age", "20");
   map.put("sex", "1");
   jedis.hmset("userInfo", map);
  
   // 获取一条数据
   String name = jedis.hget("userInfo", "name");
   System.out.println(name);
   
   // 获取多条数据
   List<String> list = jedis.hmget("userInfo", "age", "sex");
   for (String str : list) {
      System.out.println(str);
   }
   
   // 获取Hash类型所有的数据
   Map<String, String> userMap = jedis.hgetAll("userInfo");
   for (Entry<String, String> userInfo : userMap.entrySet()) {
      System.out.println(userInfo.getKey() + "--" + userInfo.getValue());
   }
  
   // 删除 用于删除hash类型数据
   //jedis.hdel("userInfo", "name");
}

4. Jedis操作list类型

 // 3.操作list
   @Test
   public void testList() {
     // 左添加(上)
   	// jedis.lpush("students", "Wang Wu", "Li Si");
      
     // 右添加(下)
   	//jedis.rpush("students", "Zhao Liu");

      
      // 获取start起始下标 end结束下标 包含关系
      List<String> students = jedis.lrange("students", 0, 2);
      for (String stu : students) {
         System.out.println(stu);
      }
      
      // 获取总条数
      Long total = jedis.llen("students");
      System.out.println("总条数:" + total);
   
      // 删除单条 删除列表中第一次出现的Li Si
   	 // jedis.lrem("students", 1, "Li Si");

     // 删除多条
    // jedis.del("students");
   }

5. Jedis操作set类型

/**
     * 操作set
     */
@Test
public void testSet(){
    //添加数据
    jedis.sadd("letters","aaa","bbb","ccc","ddd","eee");
    //获取数据
    Set<String> set = jedis.smembers("letters");
    set.forEach(System.out::println);
    //获取总条数
    Long total = jedis.scard("letters");
    System.out.println(total);
    //删除数据
    jedis.srem("letters","aaa","bbb");
}

6. Jedis操作sortedset数据类型

/**
     * 操作sorted set
     */
@Test
public void testSortedSet(){
    //添加数据
    Map<String,Double> map = new HashMap<>();
    map.put("zhangsan",7D);
    map.put("lisi",3D);
    map.put("wangwu",5D);
    map.put("zhaoliu",6D);
    map.put("tianqi",1D);
    jedis.zadd("score",map);
    /**
         * 获取数据
         *  第一个参数:redis的key
         *  第二个参数:起始下标
         *  第三个参数:结束下标
         */
    Set<String> set = jedis.zrange("score", 0, 4);
    set.forEach(System.out::println);
    //获取总条数
    Long total = jedis.zcard("score");
    System.out.println(total);
    //删除数据
    jedis.zrem("score","zhangsan","wangwu");
}

八、层级目录+失效时间

Redis中以层级关系、目录形式存储数据

    /**
     * 层级目录形式存储数据
     */
    @Test
    public void testDir(){
        jedis.set("cart:user01:item01","apple");
        System.out.println(jedis.get("cart:user01:item01"));
    }

设置key的失效时间

Redis 有四个不同的命令可以用于设置键的生存时间(键可以存在多久)或过期时间(键什么时候会被删除) :

EXPlRE :用于将键 key 的生存时间设置为 ttl 秒。

PEXPIRE :用于将键 key 的生存时间设置为 ttl 毫秒。

EXPIREAT < timestamp>:用于将键 key 的过期时间设置为 timestamp 所指定的秒数时间戳。

PEXPIREAT < timestamp >:用于将键 key 的过期时间设置为 timestamp 所指定的毫秒数时间戳。

TTL:获取的值为-1说明此 key 没有设置有效期,当值为-2时证明过了有效期。

    /**
     * key的失效时间
     */
    @Test
    public void testExpire(){
        //给已经存在key设置失效时间
        // jedis.set("code","test");
        //设置失效时间,单位秒
        // jedis.expire("code",30);
        //设置失效时间,单位毫秒
        // jedis.pexpire("code",30000);
        //查看失效时间,单位秒。-1为不失效,-2为已失效
        // Long ttl = jedis.ttl("code");
        // System.out.println(ttl);

        //添加key的时候设置失效时间
        //设置失效时间,单位秒
        // jedis.setex("code",30,"test");
        //设置失效时间,单位毫秒
        // jedis.psetex("code",30000,"test");
        //查看失效时间,单位毫秒
        // Long pttl = jedis.pttl("code");
        // System.out.println(pttl);

        //nx,xx的用法
        SetParams setParams = new SetParams();
        //不存在的时候才能设置成功
        // setParams.nx();
        // 存在的时候才能设置成功
        setParams.xx();
        //设置失效时间,单位秒
        // setParams.ex(30);
        //查看失效时间,单位毫秒
        setParams.px(30000);
        jedis.set("code","test",setParams);
    }

九、获取所有key&事务&删除

    /**
     * 查询所有key
     */
    @Test
    public void testAllKey(){
        //当前数据库key的数量
        Long size = jedis.dbSize();
        System.out.println(size);
        //查询当前数据库的所有key
        Set<String> set = jedis.keys("*");
        set.forEach(System.out::println);
    }


    /**
     * 事务
     */
    @Test
    public void testMulti(){
        //开启事务
        Transaction tx = jedis.multi();
        tx.set("tel","10086");
        //提交事务
        tx.exec();
        //回滚事务
        // tx.discard();
    }

十、Jedis操作byte数组

操作byte

SerializeUtil.java

package com.xxxx.redisdemo.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 序列化工具类
 */
public class SerializeUtil {
   
   /**
    * 将java对象转换为byte数组 序列化过程
    */
   public static byte[] serialize(Object object) {
      ObjectOutputStream oos = null;
      ByteArrayOutputStream baos = null;
      try {
         // 序列化
         baos = new ByteArrayOutputStream();
         oos = new ObjectOutputStream(baos);
         oos.writeObject(object);
         byte[] bytes = baos.toByteArray();
         return bytes;
      } catch (Exception e) {
         e.printStackTrace();
      }
      return null;
   }

   /**
    * 将byte数组转换为java对象  反序列化
    */
   public static Object unserialize(byte[] bytes) {
      if(bytes == null)return null;
      ByteArrayInputStream bais = null;
      try {
         // 反序列化
         bais = new ByteArrayInputStream(bytes);
         ObjectInputStream ois = new ObjectInputStream(bais);
         return ois.readObject();
      } catch (Exception e) {
         e.printStackTrace();
      }
      return null;
   }
}

User.java

package com.xxxx.redisdemo.pojo;

import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 9148937431079191022L;
    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

JedisTest.java

    /**
     * 操作byte数组
     */
    @Test
    public void testByte(){
        User user = new User();
        user.setId(2);
        user.setUsername("zhangsan");
        user.setPassword("123456");
        //序列化为byte数组
        byte[] userKey = SerializeUtil.serialize("user:" + user.getId());
        byte[] userValue = SerializeUtil.serialize(user);
        //存入redis
        jedis.set(userKey,userValue);
        //取出数据
        byte[] bytes = jedis.get(userKey);
        //反序列化
        User user1 = (User) SerializeUtil.unserialize(bytes);
        System.out.println(user1);
    }

讲解三:SpringDataRedis

一、简介

Spring Data Redis是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,

对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。

官网地址:Spring Data Redis

maven坐标:

<dependency>
    <groupId>org.springframework.data</groupId>

    <artifactId>spring-data-redis</artifactId>

    <version>2.4.8</version>

</dependency>

SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。

Spring Boot提供了对应的Starter,maven坐标:

<dependency>
    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

Spring Data Redis中提供了一个高度封装的类:RedisTemplate,

针对 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:

  • ValueOperations:简单K-V操作
  • SetOperations:set类型数据操作
  • ZSetOperations:zset类型数据操作
  • HashOperations:针对hash类型的数据操作
  • ListOperations:针对list类型的数据操作

二、创建项目

自行创建一个 SpringBoot 项目

三、添加依赖

	<dependencies>
		<!--spring-data-redis依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<!-- commons-pool2 对象池依赖 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
		</dependency>
		<!--web组件-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--test组件-->
		<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>

四、添加application.yml配置文件

spring:
  redis:  #redis配置
    # Redis服务器地址
    host: 192.168.136.160
    # Redis服务器端口
    port: 6379
    # Redis服务器密码
    password: root
    # Redis服务器0号数据库
    database: 0
    # 连接超时时间
    timeout: 10000ms
    lettuce:
      pool:
        # 最大连接数,默认8
        max-active: 1024
        # 最大连接阻塞等待时间,单位毫秒,默认-1ms
        max-wait: 10000ms
        # 最大空闲连接,默认8
        max-idle: 200
        # 最小空闲连接,默认0
        min-idle: 5

五、Lettuce和Jedis的区别

Jedis 是一个优秀的基于 Java 语言的 Redis 客户端,但是,其不足也很明显:

Jedis 在实现上是直接连接 RedisServer,在多个线程间共享一个 Jedis 实例时是线程不安全的,

如果想要在多线程场景下使用 Jedis ,需要使用连接池,每个线程都使用自己的 Jedis 实例,

当连接数量增多时,会消耗较多的物理资源。

Lettuce 则完全克服了其线程不安全的缺点: Lettuce 是基于 Netty 的连接(StatefulRedisConnection),

Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。

多个线程可以共享一个连接 实例,而不必担心多线程并发问题。

它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集 群,流水线,自动重新连接和

Redis 数据模型。

六、测试环境测试环境是否搭建成功

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringDataRedisApplication.class)
public class SpringDataRedisApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    public void initconn() {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        ops.set("username","lisi");
        ValueOperations<String, String> value = redisTemplate.opsForValue();
        value.set("name","wangwu");
        System.out.println(ops.get("name"));
   }
}

七、SpringDataRedis序列化模板

1. 序列化问题

默认情况下的模板 RedisTemplate,

默认序列化使用的是JdkSerializationRedisSerializer,存储二进制字节码。

这时需要自定义模板,当自定义模板后又想存储 String 字符串时,可以使StringRedisTemplate的方式,他们俩

并不冲突。

要把 domain object 做为 key-value 对保存在 redis 中,就必须要解决对象的序列化问题。

Spring Data Redis给我们 提供了一些现成的方案:

2. 序列化解决方案

1. JdkSerializationRedisSerializer使用JDK提供的序列化功能。

优点:是反序列化时不需要提供类型信息(class),

但缺点是序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗 Redis 服务器的大量内存。

2. Jackson2JsonRedisSerializer 使用 Jackson 库将对象序列化为JSON字符串

优点:是速度快,序列化后的字符串短小精悍。

缺点:也非常致命,那就是此类的构造函数中有一个类型参数,必须提供要序列化对象的类型信息(.class对象)。

通过查看源代码,发现其只在反序列化过程中用到了类型信息。

3. GenericJackson2JsonRedisSerializer通用型序列化,这种序列化方式不用自己手动指定对象的 Class

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        //为string类型key设置序列器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //为string类型value设置序列器
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        //为hash类型key设置序列器
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        //为hash类型value设置序列器
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
   }
}
//序列化
@Test
public void testSerial(){
    User user = new User();
    user.setId(1);
    user.setUsername("张三");
    user.setPassword("111");
    ValueOperations<String, Object> value = redisTemplate.opsForValue();
    value.set("userInfo",user);
    System.out.println(value.get("userInfo"));
}

3. 自定义序列化

RedisTemplate可以接收任意Object作为值写入Redis:

只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:

缺点:

  • 可读性差
  • 内存占用较大

我们可以自定义RedisTemplate的序列化方式,代码如下:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(connectionFactory);
        // 创建JSON序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = 
                                        new GenericJackson2JsonRedisSerializer();
        // 设置Key的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置Value的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);
        // 返回
        return template;
    }
}

这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图:

整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,

并且查询时能自动把JSON反序列化为Java对象。

不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。

这会带来额外的内存开销。

4. StringRedisTemplate

为了节省内存空间,我们可以不使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储

String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

因为存入和读取时的序列化及反序列化都是我们自己实现的,SpringDataRedis就不会将class信息写入Redis了。

这种用法比较普遍,因此SpringDataRedis就提供了RedisTemplate的子类:StringRedisTemplate,

它的key和value的序列化方式默认就是String方式。

省去了我们自定义RedisTemplate的序列化方式的步骤,而是直接使用:

@Autowired
private StringRedisTemplate stringRedisTemplate;
// JSON序列化工具
private static final ObjectMapper mapper = new ObjectMapper();

@Test
void testSaveUser() throws JsonProcessingException {
    // 创建对象
    User user = new User("虎哥", 21);
    // 手动序列化
    String json = mapper.writeValueAsString(user);
    // 写入数据
    stringRedisTemplate.opsForValue().set("user:200", json);

    // 获取数据
    String jsonUser = stringRedisTemplate.opsForValue().get("user:200");
    // 手动反序列化
    User user1 = mapper.readValue(jsonUser, User.class);
    System.out.println("user1 = " + user1);
}

八、SpringData操作Redis

1. 操作string数据类型

// 1.操作String
@Test
public void testString() {
    ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    // 添加一条数据
    valueOperations.set("username", "zhangsan");
    valueOperations.set("age", "18");
    //redis中以层级关系、目录形式存储数据
    valueOperations.set("user:01", "lisi");
    valueOperations.set("user:02", "wangwu");
    // 添加多条数据
    Map<String, String> userMap = new HashMap<>();
    userMap.put("address", "bj");
    userMap.put("sex", "1");
    valueOperations.multiSet(userMap);
    // 获取一条数据
    Object username = valueOperations.get("username");
    System.out.println(username);
    // 获取多条数据
    List<String> keys = new ArrayList<>();
    keys.add("username");
    keys.add("age");
    keys.add("address");
    keys.add("sex");
    List<Object> resultList = valueOperations.multiGet(keys);
    for (Object str : resultList) {
        System.out.println(str);
   }
    // 删除
    redisTemplate.delete("username");
}

2. 操作hash数据类型

// 2.操作Hash
@Test
public void testHash() {
    HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
    /*

     * 添加一条数据
     *     参数一:redis的key
     *     参数二:hash的key
     *     参数三:hash的value
     */
    hashOperations.put("userInfo","name","lisi");
    // 添加多条数据
    Map<String, String> map = new HashMap();
    map.put("age", "20");
    map.put("sex", "1");
    hashOperations.putAll("userInfo", map);
    // 获取一条数据
    String name = hashOperations.get("userInfo", "name");
    System.out.println(name);
    // 获取多条数据
    List<String> keys = new ArrayList<>();
    keys.add("age");
    keys.add("sex");
    List<String> resultlist =hashOperations.multiGet("userInfo", keys);
    for (String str : resultlist) {
        System.out.println(str);
   }
    // 获取Hash类型所有的数据
    Map<String, String> userMap = hashOperations.entries("userInfo");
    for (Entry<String, String> userInfo : userMap.entrySet()) {
        System.out.println(userInfo.getKey() + "--" + userInfo.getValue());
   }
    // 删除 用于删除hash类型数据
    hashOperations.delete("userInfo", "name");
}

3. 操作list数据类型

// 3.操作list
@Test
public void testList() {
    ListOperations<String, Object> listOperations = redisTemplate.opsForList();
    // 左添加(上)
    // listOperations.leftPush("students", "Wang Wu");
    // listOperations.leftPush("students", "Li Si");
    
    // 左添加(上) 把value值放到key对应列表中pivot值的左面,如果pivot值存在的话
    // listOperations.leftPush("students", "Wang Wu", "Li Si");
    
    // 右添加(下)
    // listOperations.rightPush("students", "Zhao Liu");
    // 获取 start起始下标 end结束下标 包含关系
    List<Object> students = listOperations.range("students", 0,2);
    for (Object stu : students) {
        System.out.println(stu);
    }

    // 根据下标获取
    Object stu = listOperations.index("students", 1);
    System.out.println(stu);
    
    // 获取总条数
    Long total = listOperations.size("students");
    System.out.println("总条数:" + total);
    
    // 删除单条 删除列表中存储的列表中几个出现的Li Si。
    listOperations.remove("students", 1, "Li Si");

    // 删除多条
    redisTemplate.delete("students");
}

4. 操作set数据类型

// 4.操作set-无序
@Test
public void testSet() {
    SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
    
    // 添加数据
    String[] letters = new String[]{"aaa", "bbb", "ccc", "ddd", "eee"};
    //setOperations.add("letters", "aaa", "bbb", "ccc", "ddd", "eee");
    setOperations.add("letters", letters);
    
    // 获取数据
    Set<Object> let = setOperations.members("letters");
    for (Object letter: let) {
        System.out.println(letter);
   }
   
    // 删除
    setOperations.remove("letters", "aaa", "bbb");
}

5. 操作sortedset数据类型

// 5.操作sorted set-有序
@Test
public void testSortedSet() {
    ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
    ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<Object>("zhangsan", 7D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<Object>("lisi", 3D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<Object>("wangwu", 5D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple4 = new DefaultTypedTuple<Object>("zhaoliu", 6D);
    ZSetOperations.TypedTuple<Object> objectTypedTuple5 = new DefaultTypedTuple<Object>("tianqi", 2D);
    Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<ZSetOperations.TypedTuple<Object>>();
    tuples.add(objectTypedTuple1);
    tuples.add(objectTypedTuple2);
    tuples.add(objectTypedTuple3);
    tuples.add(objectTypedTuple4);
    tuples.add(objectTypedTuple5);
    
    // 添加数据
    zSetOperations.add("score", tuples);
    
    // 获取数据
    Set<Object> scores = zSetOperations.range("score", 0, 4);
    for (Object score: scores) {
        System.out.println(score);
   }
    // 获取总条数
    Long total = zSetOperations.size("score");
    System.out.println("总条数:" + total);
    
    // 删除
    zSetOperations.remove("score", "zhangsan", "lisi");
}

6. 获取所有key+设置key失效时间

获取所有key&删除

// 获取所有key
@Test
public void testAllKeys() {
    // 当前库key的名称
    Set<String> keys = redisTemplate.keys("*");
    for (String key: keys) {
        System.out.println(key);
   }
}
// 删除
@Test
public void testDelete() {
    // 删除 通用 适用于所有数据类型
    redisTemplate.delete("score");
}

设置key的失效时间

@Test
public void testEx() {
    ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    // 方法一:插入一条数据并设置失效时间
    valueOperations.set("code", "abcd", 180, TimeUnit.SECONDS);
    // 方法二:给已存在的key设置失效时间
    boolean flag = redisTemplate.expire("code", 180, TimeUnit.SECONDS);
    // 获取指定key的失效时间
    Long l = redisTemplate.getExpire("code");
}

7. 通用操作

/**
 * 通用操作,针对不同的数据类型都可以操作
*/
@Test
public void testCommon(){
    //获取Redis中所有的key
    Set<String> keys = redisTemplate.keys("*");
    for (String key : keys) {
        System.out.println(key);
    }

    //判断某个key是否存在
    Boolean project = redisTemplate.hasKey("itcast");
    System.out.println(project);

    //删除指定key
    redisTemplate.delete("myZset");

    //获取指定key对应的value的数据类型
    DataType dataType = redisTemplate.type("myset");
    System.out.println(dataType.name());

}

九、SpringDataRedis整合哨兵

application.yml

spring:
   redis:
        # Redis服务器地址
       host: 192.168.10.100
        # Redis服务器端口
       port: 6379
        # Redis服务器端口
       password: root
        # Redis服务器端口
       database: 0
        # 连接超时时间
       timeout: 10000ms
       lettuce:
           pool:
                # 最大连接数,默认8
               max-active: 1024
                # 最大连接阻塞等待时间,单位毫秒,默认-1ms
               max-wait: 10000ms
                # 最大空闲连接,默认8
               max-idle: 200
                # 最小空闲连接,默认0
               min-idle: 5

        #哨兵模式
       sentinel:
            #主节点名称
           master: mymaster
            #节点
           nodes:  192.168.10.100:26379,192.168.10.100:26380,192.168.10.100:26381

Bean注解配置

@Bean
public RedisSentinelConfiguration redisSentinelConfiguration(){
    RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration()
            // 主节点名称
           .master("mymaster")
            // 主从服务器地址
           .sentinel("192.168.10.100", 26379)
           .sentinel("192.168.10.100", 26380)
           .sentinel("192.168.10.100", 26381);
    // 设置密码
    sentinelConfig.setPassword("root");
    return sentinelConfig;
}

十、知识小结

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做

SpringDataRedis,官网地址:Spring Data Redis

  • 提供了对不同Redis客户端的整合(Lettuce和Jedis)
  • 提供了RedisTemplate统一API来操作Redis
  • 支持Redis的发布订阅模型
  • 支持Redis哨兵和Redis集群
  • 支持基于Lettuce的响应式编程
  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。

并且将不同数据类型的操作API封装到了不同的类型中:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2172151.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IoT网关的主要功能有哪些?天拓四方

在数字化浪潮席卷全球的今天&#xff0c;物联网&#xff08;IoT&#xff09;技术凭借其独特的优势&#xff0c;逐渐在各个领域展现出强大的生命力。而IoT网关&#xff0c;作为连接物理世界与数字世界的桥梁&#xff0c;其在物联网体系中的作用愈发凸显。 一、数据聚合与预处理…

qt 高并发编程及同步

高并发编程是指在同一时间处理多个任务的能力&#xff0c;通常用于提升应用程序的性能和响应速度。Qt提供了一系列强大的工具和类来实现高并发编程&#xff0c;包括多线程、异步编程和任务调度。 一、继承QThread #include <QThread>class Worker : public QThread {voi…

基于springcloud的药品销售系统

文未可获取一份本项目的java源码和数据库参考。 一、选题背景与意义 1. 选题背景 在日常医药管理中&#xff0c;面对众多的药品和众多不同需求的顾客&#xff0c;每天都会产生大量的数据信息。以传统的手工方式来处理这些信息&#xff0c;操作比较繁琐&#xff0c;且效率低下…

重头开始嵌入式第四十四天(硬件 ARM裸机开发)

目录 裸机开发 一、开发背景 二、开发特点 三、开发流程 四、应用领域 使用的软件硬件 软件&#xff1a;keil 硬件&#xff1a;三星S3C2440A JTAG 开发原理 ​编辑 开发步骤 ​编辑 点亮小灯 按键控制亮灭 裸机开发 ARM 裸机开发是指在没有操作系统的情况…

CUDAExample: 波纹示例

需要用到的已经封装好的辅助类&#xff1a; CPUAnimBitmap 定义个grid 和 block 的维度都是二维的 #include"cpu_anim.h" #include "cuda_runtime.h" #include <device_launch_parameters.h>#define DIM 512 static void CheckCudaErrorAux(const …

numpy is not available

在测试第一个程序的时候&#xff0c;出现Numpy is not available的错误&#xff0c;根据博客的办法知道是因为numpy与pytorch版本不一致造成的。 安装的时候&#xff0c;安装的是最新版的numpy&#xff0c;检查numpy的版本为2.1.1版。 根据pytorch与numpy版本对应表。我的pyt…

【Python报错已解决】NameError: name ‘torchvision‘ is not defined

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

AI知识库如何重塑电商行业的产品推荐系统

在数字化浪潮的推动下&#xff0c;电子商务行业正经历着前所未有的变革。其中&#xff0c;产品推荐系统作为连接消费者与商品的桥梁&#xff0c;其智能化与个性化水平直接影响着用户体验、转化率乃至整个平台的竞争力。随着人工智能&#xff08;AI&#xff09;技术的飞速发展&a…

大豆重测序-文献精读53

Natural variation in GmSW17 controls seed size in soybean GmSW17的自然变异控制大豆种子的大小 摘要 种子大小/重量在决定作物产量中起着重要作用&#xff0c;但在大豆中&#xff0c;仅有少数控制种子大小的基因被鉴定出来。在本研究中&#xff0c;我们进行了全基因组关联…

Java项目——苍穹外卖总结

附上本人代码连接&#xff1a;xiaoming325/sky-take-out (github.com) 项目概述 此项目是一个外卖点餐项目&#xff0c;分为商家端&#xff08;管理员端&#xff09;和用户端&#xff0c;商家端是一个网站&#xff0c;用户端是一个微信小程序&#xff0c;由于微信小程序没有上…

Java ERP管理系统源码解析:微服务架构实践Spring Cloud Alibaba与Spring Boot

在当今数字化浪潮的推动下&#xff0c;企业对于高效、稳定且易于扩展的管理系统需求日益增长。为了满足这一需求&#xff0c;我们精心打造了一款基于Java技术的鸿鹄ERP&#xff08;Enterprise Resource Planning&#xff09;管理系统。该系统充分利用了Spring Cloud Alibaba、S…

【刷题5】在排序数组中查找元素的第一个和最后一个位置

目录 一、题目解析二、思路—二分查找(二段性)1、查找最左端区间2、查找最右端区间 三、代码 一、题目解析 题目理解&#xff1a; 返回begin和end&#xff0c;是数组下标 二、思路—二分查找(二段性) 1、查找最左端区间 left和right移动问题&#xff1a; 循环条件问题&…

探索甘肃非遗:Spring Boot网站开发案例

1 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规范化管理。这样的大环境让那些止步不前&#…

2024年中国电子学会青少年软件编程(Python)等级考试(二级)核心考点速查卡

考前练习 2024年03月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;二级&#xff09;答案 解析 2024年06月中国电子学会青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;二级&#xff09;答案 解析 知识点描述 …

如何利用 Kafka,实时挖掘企业数据的价值?

首先&#xff0c;问读者老爷们一个简单的问题&#xff0c;如果你需要为你的数据选择一个同时具备高吞吐 、数据持久化、可扩展的数据传递系统&#xff0c;你会选择什么样的工具或架构呢&#xff1f; 答案非常显而易见&#xff0c;那就是 Kafka&#xff0c;不妨再次套用一个被反…

vue el-cascader 级联选择器 多选实现默认勾选并回显前子项

文章目录 前言代码实现总结 前言 最近实现一个需求 接收传递过来的值 并在 el-cascader级联选择器 上 勾选回显出来 记录下代码实现 代码实现 <template><div id"app"><el-card class"box-card"><el-formref"form2"label…

YOLOv7改进之MAE主干: 超强ConvNeXtV2 升级版结构,当MAE+YOLO卷积高效涨点

目录 1,原理概述 2,代码改进 新增一个convnextv2.py文件,增加以下代码 修改部分 第二步:在yolo.py中加入以下代码 然后在 在yolo.py中配置找到./models/yolo.py文件下里的parse_model函数,将类名加入进去 参考代码 YOLOv7网络配置文件 1,原理概述 原文:https://…

MATLAB绘图基础9:多变量图形绘制

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 9.多变量图形绘制 9.1 气泡图 气泡图用于展示三个或更多变量变量之间的关系&#xff0c;气泡图的组成要素&#xff1a; 横轴( X {\rm X} X轴)&#xff1a;表示数据集中的一个变量&#xff0c…

LED显示屏如何通过FMEA进行风险分析:打造无忧显示新境界

LED显示屏作为高科技产品&#xff0c;其性能受到多种因素的影响&#xff0c;包括但不限于设计缺陷、材料质量、制造工艺、使用环境等。任何环节的疏漏都可能导致显示屏出现亮度不均、色彩失真、故障频发等问题&#xff0c;进而影响用户体验和品牌形象。因此&#xff0c;通过FME…

信息安全工程师(23)网络安全体系相关模型

前言 网络安全体系相关模型是描述网络安全体系如何实现的理论框架和抽象模型&#xff0c;它们为理解和设计网络安全解决方案提供了系统化的方法。 1. PDR模型 提出者&#xff1a;美国国际互联网安全系统公司(ISS)核心内容&#xff1a;保护(Protection)、检测(Detection)、响应(…