Redis:Java客户端

news2024/9/23 3:28:00

前言

"在当今大数据和高并发的应用场景下,对于数据缓存和高效访问的需求日益增长。而Redis作为一款高性能的内存数据库,以其快速的读写能力和丰富的数据结构成为众多应用的首选。与此同时,Java作为广泛应用于企业级开发的编程语言,在与Redis的集成中扮演着重要的角色。因此,掌握如何使用Redis的Java客户端成为了Java开发人员的重要技能之一。

本篇博客将详细介绍Redis的Java客户端,包括其基本概念、使用方法和常见应用场景。我们将通过实际的代码示例和应用案例,带领读者深入了解如何在Java项目中使用Redis进行数据缓存、会话管理等操作,以及如何利用Java客户端与Redis进行交互。

一、前期准备

1、新建项目,结构如下

2、导入依赖
 <!-- 放在最前面依赖,依据依赖的最短路径原则,
             将不在使用spring-data中的slf4j,否则
             会引发冲突-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.3.8</version>
        </dependency>

        <!-- spring data框架,提供了对redis的整合支持,
             内部支持lettuce以及Jedis客户端-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>2.5.6</version>
        </dependency>

        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>6.2.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

 让我逐个解释一下每个依赖项的作用:

  1. logback-classic: Logback是一个用于记录日志的框架,logback-classic是其经典模块,提供了SLF4J(Simple Logging Facade for Java)的实现。通过使用logback-classic,你可以在应用程序中配置和记录日志。

  2. spring-data-redis: 这是Spring Data框架的一部分,它提供了对Redis数据库的集成支持。使用spring-data-redis,你可以轻松地使用Spring框架与Redis进行交互,执行各种操作,如存储和检索数据。

  3. lettuce-core: Lettuce是一个高性能的Java Redis客户端库,用于与Redis服务器进行通信。lettuce-core是Lettuce的核心模块,它提供了与Redis的连接管理、命令执行和数据传输相关的功能。

  4. lombok: Lombok是一个Java库,通过注解来减少代码的冗余。它提供了一些注解,可以自动生成Java类的常见方法(如getter、setter、equals、hashCode等),从而简化了开发流程。

  5. junit: JUnit是一个用于编写和运行单元测试的Java框架。它提供了一组用于验证代码是否按预期运行的断言方法和测试运行器。使用JUnit,你可以编写测试用例来验证你的代码的正确性和健壮性。

二、编写 Redis 配置类

1、RedisConfig 配置类

@Configuration
public class RedisConfig {

    @Bean
    public LettuceConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration("localhost", 6379);
        configuration.setPassword(RedisPassword.of("qiu"));
        configuration.setDatabase(0);
        return new LettuceConnectionFactory(configuration);
    }

    /**
     * 装配RedisTemplate,并自定义序列化器
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //设置连接工厂
        redisTemplate.setConnectionFactory(connectionFactory());
        //自定义key的序列化器(使用字符串序列化器)
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        //自定义value的序列化器(使用json序列化器)
        redisTemplate.setValueSerializer(RedisSerializer.json());
        redisTemplate.setHashValueSerializer(RedisSerializer.json());
        //返回redisTempalte
        return redisTemplate;
    }
}

这段代码是一个Redis的配置类,用于配置与Redis的连接和序列化方式。 

  1. @Configuration 注解表示这是一个配置类,用于定义一个或多个 bean 对象。
  2. @Bean 注解表示下面的方法将会返回一个 bean 对象,并注册到应用程序上下文中,以供其他组件使用。

首先,我们定义了一个名为 connectionFactory 的方法,返回一个 LettuceConnectionFactory 对象。LettuceConnectionFactory 是连接 Redis 服务器的工厂类。在这个方法中,我们创建了一个 RedisStandaloneConfiguration 对象,用于指定 Redis 服务器的主机名和端口号。然后,我们设置了 Redis 的密码(如果有密码),并指定要连接的数据库索引。最后,我们将这个配置对象传递给 LettuceConnectionFactory 的构造函数,创建并返回连接工厂。

接下来,我们定义了一个名为 redisTemplate 的方法,返回一个 RedisTemplate<String, Object> 对象。RedisTemplate 是 Spring 提供的用于操作 Redis 的模板类。在这个方法中,我们创建了一个新的 RedisTemplate 对象,并设置其连接工厂为前面创建的 LettuceConnectionFactory 对象。

为了正确地序列化键和值,我们使用了一些序列化器:

  • 使用 RedisSerializer.string() 方法来设置键和哈希键的序列化器,使它们以字符串形式进行序列化和反序列化。
  • 使用 RedisSerializer.json() 方法来设置值和哈希值的序列化器,以支持 JSON 格式的序列化和反序列化。

最后,我们返回了配置好的 RedisTemplate 对象。

通过这样的配置,我们可以在应用程序中注入 RedisTemplate 对象,并使用它来执行 Redis 的操作,如存储、获取、删除数据等。此外,键和值的序列化方式也被正确地配置,以便在 Redis 中存储和传输数据时能够正确地进行序列化和反序列化操作。

 三、编写 RedisUtil 工具类


public class RedisUtilr {

    /**
     * redis 的连接对象
     * 定义了一个名为connection的私有静态变量,
     * 用于保存 Redis 的连接对象。
     */
    private static StatefulRedisConnection connection;

    /**
     * 使用 Redis 客户端库 lettuce 创建一个RedisURI实例,设置 Redis 服务的相关信息,
     * 然后使用 RedisClient 来创建 Redis 连接对象,并将其保存到connection静态变量中。
     * 在静态代码块中进行初始化,确保在类加载时创建 Redis 连接对象,并且只创建一次,
     * 以提高应用程序的性能和效率。
     */
    static {
        // 初始化连接的 uri,创建一个RedisURI实例,
        // 表示Redis服务的地址和配置信息。这里使用lettuce作为客户端库。
        RedisURI redisURI = RedisURI.Builder
                .redis("lettuce")
                // 设置Redis服务的主机地址为127.0.0.1。
                .withHost("127.0.0.1")
                // 设置Redis服务的端口号为6379。
                .withPort(6379)
                // 设置Redis服务的密码为123456。
//                .withPassword("123456")
                // 设置Redis服务的数据库编号为0。
                .withDatabase(0)
                // 设置Redis服务的超时时间为2秒。
                .withTimeout(Duration.ofSeconds(2))
                .build();

        // 初始化连接对象并设置自定义序列化器
        connection = RedisClient.create(redisURI).connect(new ObjectRedisSerializer());
    }

    /**
     * 从连接中
     * @return
     */
    public static RedisCommands getCommands(){
        // 获取一个同步命令
        return connection.sync();
    }

}

该工具类具有以下功能:

  1. 创建一个RedisURI实例,用于设置Redis服务的相关信息,如主机地址、端口号、密码、数据库编号和超时时间。
  2. 使用RedisClient类和RedisURI实例创建一个Redis连接对象,并将连接对象保存在connection静态变量中。
  3. 提供一个静态方法getCommands(),用于获取一个与Redis数据库进行同步通信的RedisCommands对象。

通过使用这个工具类,你可以更方便地进行与Redis数据库的交互操作,例如执行各种命令、读取和写入数据等。

四、自定义序列化器


public class ObjectRedisSerializer implements RedisCodec<String,Object> {

    /**
     * 这个方法将 key 从 redis 取出来的时候转换为字符串类型
     * 将 key 的字节缓冲(ByteBuffter)转换为字节缓冲
     * @param byteBuffer
     * @return
     */
    @Override
    public String decodeKey(ByteBuffer byteBuffer) {
        ByteBuffer allocate = ByteBuffer.allocate(byteBuffer.capacity());
        allocate.put(byteBuffer);

        // 将字节数组以 UTF-8 的编码转换成 string 并返回
        return new String(allocate.array(), StandardCharsets.UTF_8);
    }

    /**
     * 从 redis 中取出的字节数组转换成任意的 Object 对象
     * @param byteBuffer
     * @return
     */
    @Override
    public Object decodeValue(ByteBuffer byteBuffer) {
        // 先分配系统内存空间
        ByteBuffer allocate = ByteBuffer.allocate(byteBuffer.capacity());
        allocate.put(byteBuffer);
        // 构建字节数组的输入流,这样就可以在 jvm 的内存中将这个字节数组
        // 反序列化为任意的 Object 对象
        try(ByteArrayInputStream bais = new ByteArrayInputStream(allocate.array())){
            // 再通过对象输入流将其转换即可
            ObjectInputStream objectInputStream = new ObjectInputStream(bais);
            return objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e){
            throw new RuntimeException("无法反序列化value",e);
        }

    }

    /**
     * 将字符串的 key 序列化成字节数组保存到 redis
     * @param key
     * @return
     */
    @Override
    public ByteBuffer encodeKey(String key) {
        return ByteBuffer.wrap(key.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 将 Object 序列化成字节数组保存到 redis 中
     * @param value
     * @return
     */
    @Override
    public ByteBuffer encodeValue(Object value) {
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream()){
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(baos);
            // 将对象写入流中变成字节数组
            objectOutputStream.writeObject(value);
            // 从流中获取字节数组
            byte[] bytes = baos.toByteArray();
            // 将字节数组包装成 ByteBuffer 对象并返回
            return ByteBuffer.wrap(bytes);
        } catch (IOException e){
            throw new RuntimeException("无法序列化value",e);
        }
    }
}

这段代码实现了一个自定义的 Redis 序列化器(RedisSerializer),用于将键和值在 Redis 和 Java 对象之间进行序列化和反序列化操作。

该类实现了 RedisCodec 接口,并指定了其泛型类型为 <String, Object>,表示键为字符串类型,值为任意对象类型。

在该类中,有四个方法需要实现:

  1. decodeKey 方法用于将从 Redis 中取出的字节缓冲(ByteBuffer)转换为字符串类型的键。它先创建一个与传入参数相同容量的 ByteBuffer 对象,然后将传入参数中的字节复制到新创建的 ByteBuffer 中,并使用 UTF-8 编码将字节数组转换为字符串并返回。

  2. decodeValue 方法用于将从 Redis 中取出的字节缓冲转换为任意对象类型的值。它先创建一个与传入参数相同容量的 ByteBuffer 对象,然后将传入参数中的字节复制到新创建的 ByteBuffer 中。接下来,它使用 ByteArrayInputStream 将字节数组包装成输入流,再通过 ObjectInputStream 对象将输入流反序列化为对象并返回。

  3. encodeKey 方法用于将字符串类型的键序列化为字节数组保存到 Redis 中。它将键转换为字节数组,并使用 wrap 方法将字节数组包装成 ByteBuffer 对象并返回。

  4. encodeValue 方法用于将任意对象类型的值序列化为字节数组保存到 Redis 中。它使用 ByteArrayOutputStream 创建一个输出流,然后通过 ObjectOutputStream 将对象写入输出流,最后通过 toByteArray 方法获取字节数组,并使用 wrap 方法将字节数组包装成 ByteBuffer 对象并返回。

通过使用这个自定义的 Redis 序列化器,我们可以在 Redis 中保存任意类型的 Java 对象,并在需要时进行序列化和反序列化操作。

 五、使用java代码操作 Redis

1、set key、get key、mset、gset
 public void testLettuce(){
        // 获取 redisCommands 命令对象
        RedisCommands commands = RedisUtilr.getCommands();
        commands.set("user:1001","qiu");
        String val = (String) commands.get("user:1001");
        log.info(val);

        Map<String,Object> map = new HashMap<>();
        map.put("user:1002","user2");
        map.put("user:1003","user3");
        commands.mset(map);
        List<KeyValue> list = commands.mget("user:1001","user:1002","user:1003");
        list.forEach(System.out::println);
        list.forEach(keyValue -> log.info("---》" + keyValue.getKey()));

    }

这段代码使用了Lettuce库来连接和操作Redis数据库。以下是代码的解释:

  1. RedisUtilr.getCommands():这是一个自定义的工具类方法,用于获取Redis命令对象。

  2. commands.set("user:1001", "qiu"):通过set命令将键为"user:1001",值为"qiu"的数据存储到Redis中。

  3. commands.get("user:1001"):通过get命令获取键为"user:1001"的值,并将其赋给变量val

  4. log.info(val):将变量val的值打印到日志中。

  5. map.put("user:1002", "user2")map.put("user:1003", "user3"):将键值对"user:1002"-"user2"和"user:1003"-"user3"添加到一个Map集合中。

  6. commands.mset(map):通过mset命令批量设置多个键值对。

  7. commands.mget("user:1001", "user:1002", "user:1003"):通过mget命令批量获取多个键对应的值,并将结果存储在一个列表中。

  8. list.forEach(System.out::println):遍历列表list并将每个元素打印到控制台。

  9. log.info("---》" + keyValue.getKey()):将每个键值对的键打印到日志中。

1)运行结果

我们在控制台通过 get和mget都可以把set和mset进去的值取出来,在可视化工具中也可以查到设置进去的值。 

 2、hset、hget
 @Test
    public void testHash(){
        RedisCommands commands = RedisUtilr.getCommands();
        commands.hset("user","name","user1");
        commands.hset("user","age","21");
        commands.hset("user","sex","男");
        log.info("--->" + commands.hget("user","name"));
        log.info("--->" + commands.hget("user","age"));
        log.info("--->" + commands.hget("user","sex"));

    }

这段代码用于测试使用Lettuce库操作Redis的Hash数据结构。以下是代码的解释:

  1. RedisUtilr.getCommands():这是一个自定义的工具类方法,用于获取Redis命令对象。

  2. commands.hset("user", "name", "user1")commands.hset("user", "age", "21")commands.hset("user", "sex", "男"):分别通过hset命令向名为"user"的Hash结构中添加字段"名字"、"年龄"和"性别",并分别设置它们的值为"user1"、"21"和"男"。

  3. log.info("--->" + commands.hget("user", "name"))log.info("--->" + commands.hget("user", "age"))log.info("--->" + commands.hget("user", "sex")):分别通过hget命令获取名为"user"的Hash结构中字段"名字"、"年龄"和"性别"的值,并将它们打印到日志中。

2)运行结果
3、del
@Test
    public void testDel(){
        RedisCommands commands = RedisUtilr.getCommands();

        // 删除键
        commands.del("user:1001","user:1002","user:1003");
    }

 在示例中,使用了三个键分别为 "user:1001"、"user:1002"、"user:1003"。

该方法会将传入的键从 Redis 中删除,并返回一个表示删除成功的整数值。如果键不存在,返回的整数值为 0;如果键删除成功,返回的整数值为 1。

这段代码的作用就是删除 Redis 中的三个键 "user:1001"、"user:1002"、"user:1003" 及其关联的值。

 3)运行结果

 4、setex、expire
  @Test
    public void testExpire() throws InterruptedException {
        RedisCommands commands = RedisUtilr.getCommands();
        // 过期时间单位是秒
        commands.setex("user:1001",5,"user1");
        Thread.sleep(5000);
        log.info("--->" + commands.get("user:1001"));

        commands.set("user:1002","user2");
        // 给已存在的 key 设置过期时间
        commands.expire("user:1002",2);
    }

这段代码是一个针对Redis的过期时间设置的测试方法。首先通过RedisUtilr.getCommands()方法获取了一个RedisCommands对象,然后进行了以下操作:

  1. 使用setex方法设置了一个键为"user:1001"的值为"user1"并且设置了5秒的过期时间。
  2. 接着调用Thread.sleep(5000)来等待5秒钟,然后尝试获取"user:1001"键的值并打印输出。
  3. 使用set方法设置了一个键为"user:1002"的值为"user2"。
  4. 最后使用expire方法为已存在的"user:1002"键设置了2秒的过期时间。

在测试方法中,通过这些操作来验证Redis中键的过期时间设置是否符合预期。

 4)运行结果

 当创建出这个user:1001时,在可视化工具中查看到时,2秒后这个值就自动的销毁了。

5、序列化一个实体
 @Test
    public void testSerialize() throws JsonProcessingException {
        Product product = new Product();
        product.setProductName("iphonr");
        product.setFirm("Apple Inc");
        product.setPlace("China");
        // 将实体序列化成 JSON 字符串
        String productJson = new ObjectMapper().writeValueAsString(product);

        RedisCommands commands = RedisUtilr.getCommands();
        commands.set("product:10001",productJson);
        Object json = commands.get("product:10001");
        // 将 JSON 字符串,反序列化为 product 对象
        product = new ObjectMapper().readValue(json.toString(),Product.class);
        //commands.del("product:10001");
        log.info("---->" + product);

    }

 这段代码是一个针对Redis中对象序列化和反序列化的测试方法。具体来说,它完成了以下操作:

  1. 首先创建了一个Product对象,并设置了一些属性。
  2. 然后使用ObjectMapper将Product对象序列化成JSON字符串。
  3. 获取RedisCommands对象,并使用set方法将序列化后的JSON字符串存储到名为"product:10001"的键中。
  4. 接着使用get方法从Redis中获取"product:10001"键的值,得到的是一个JSON字符串。
  5. 使用ObjectMapper将JSON字符串反序列化为Product对象。

通过这个测试方法,可以验证在Redis中存储和读取对象的序列化和反序列化过程是否正确。

5)运行结果
6、使用自定义序列化器

新建一个实体类


@Data
public class Product implements Serializable {

    private String productName;
    private String place;
    private String firm;

}

这段代码定义了一个Java类 Product,使用了 Lombok 提供的 @Data 注解,该注解可以自动生成类的 getter、setter、equals、hashCode 和 toString 方法。

在这个 Product 类中,包含了三个成员变量 productName、place 和 firm,它们分别表示产品名称、产地和公司。

由于该类实现了 Serializable 接口,表明这个类的对象可以被序列化,也就是可以在网络上传输或者持久化到磁盘上。

测试类

 /**
     * 自定义序列化器
     */
    @Test
    public void testSerialize2(){
        Product product = new Product();
        product.setProductName("iphonr");
        product.setFirm("Apple Inc");
        product.setPlace("China");

        RedisCommands commands = RedisUtilr.getCommands();
        commands.set("user:1001",product);
        product = (Product) commands.get("user:1001");
        log.info(product.getProductName());
        log.info(product.getFirm());
        log.info(product.getPlace());

    }

 这段代码是一个针对Redis中对象序列化和反序列化的测试方法,使用了自定义的序列化器。具体来说,它完成了以下操作:

  1. 首先创建了一个Product对象,并设置了一些属性。
  2. 获取RedisCommands对象,并使用set方法将Product对象存储到名为"user:1001"的键中。由于使用了自定义的序列化器,对象会被序列化成字节数组进行存储。
  3. 使用get方法从Redis中获取"user:1001"键的值,得到的是序列化后的字节数组。
  4. 将字节数组反序列化为Product对象。
  5. 最后使用日志输出Product对象的属性。

通过这个测试方法,可以验证在Redis中使用自定义的序列化器进行对象的序列化和反序列化是否正确。

6)运行结果

六、总结

这章就已经讲完了,大家一定要注意,先打开自己的redis的服务先,才能正确的操作redis,不然会报错的。 

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

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

相关文章

三极管-开关电路-电路电子-嵌入式开发-物联网开发-电子元件

一、概述 本文我们主要讲解电子电路中十分重要的元件--三极管。三极管常常被用来当作开关或作为放大电流的作用&#xff0c;下面我们将主要围绕着其作为开关电路的使用来介绍三极管。 二、分类 学习三极管前&#xff0c;我们必须认识三极管的三级&#xff0c;包含箭头的一端为发…

【论文阅读笔记】Deep learning for time series classification: a review

【论文阅读笔记】Deep learning for time series classification: a review 摘要 在这篇文章中&#xff0c;作者通过对TSC的最新DNN架构进行实证研究&#xff0c;探讨了深度学习算法在TSC中的当前最新性能。文章提供了对DNNs在TSC的统一分类体系下在各种时间序列领域中的最成功…

(1)(1.17) Maxbotix 模拟声纳

文章目录 前言 1 连接到Pixhawk 2 通过Mission Planner进行设置 3 测试传感器 4 参数说明 前言 XL-Maxbotix-EZ 系列模拟声纳&#xff08;XL-MaxSonar-EZ0、EZ4 和 EZL0&#xff09;是相对便宜的短距离&#xff08;7m 至 10m&#xff09;测距仪&#xff0c;主要设计用于室…

Linux系统中Qt应用程序确保使用集成显卡进行图形渲染

背景&#xff1a;有一个Qt开发的应用程序&#xff0c;使用了Qt的OpenGL模块来渲染QImage加载的图片&#xff0c;当应用程序切换到图片渲染界面时&#xff0c;系统CPU占用率立马到了100%多&#xff0c;容易造成程序卡顿&#xff0c;可设备是自带集成显卡的&#xff0c;期望效果是…

7 Redis的PipeLine

PipeLine的作用是批量执行命令 redis的性能瓶颈基本上是网络 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.…

牛客::栈的压入、弹出序列

栈的压入、弹出序列 题目 输入两个整数序列&#xff0c;第一个序列表示栈的压入顺序&#xff0c;请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序&#xff0c;序列4,5,3,2,1是该压栈序列对应的一个弹出序列&…

ShardingSphere-JDBC 之数据分片详细讲解

文章目录 单一节点存储问题数据分片垂直分片水平分片 ShardingSphere-JDBC 数据分片核心概念表相关概念数据节点分片行表达式分布式主键 ShardingSphere-JDBC 数据分片原理ShardingSphere-JDBC 数据分片实现示例1、数据库表创建2、引入依赖3、配置参数4、代码示例 ShardingSphe…

FPGA实现平衡小车(文末开源!!)

FPGA平衡小车 一. 硬件介绍 底板资源: TB6612电机驱动芯片 * 2 MPU6050陀螺仪 WS2812 RGB彩色灯 * 4 红外接收头 ESP-01S WIFI 核心板 微相 A7_Lite Artix-7 FPGA开发板 电机采用的是平衡小车之家的MG310(GMR编码器)电机。底板上有两个TB6612芯片&#xff0c;可以驱动…

Python运维监控系统之架构设计

说起Python这门编程语言的作用&#xff0c;可以列举很多方面&#xff0c;其实每一门流行的编程语言都可以列举很多方面&#xff0c;但是要说起Python的主要领域&#xff0c;莫过于运维监控方面&#xff0c;在这方面有大量优秀的开源运维系统。 虽然有很多优秀的开源运维监控系统…

基于springboot实现智能热度分析和自媒体推送平台系统项目【项目源码】

基于springboot实现自媒体社区平台系统演示 系统开发平台 在该自媒体分享网站中&#xff0c;Eclipse能给用户提供更多的方便&#xff0c;其特点一是方便学习&#xff0c;方便快捷&#xff1b;二是有非常大的信息储存量&#xff0c;主要功能是用在对数据库中查询和编程。其功能…

《微信小程序开发从入门到实战》学习十九

3.3 开发创建投票页面 3.3.7 wx:for列表渲染 接下来为创建的投票页面添加一个“添加选项”的功能。需要用户输入文字&#xff0c;应该使用input组件。头投票的数量是不确定的&#xff0c;面对不确定数量的组件的情况时&#xff0c;可以使用wx:for属性对组件进行列表渲染。 使…

windows pgsql 数据库 数据目录更改

一.先停止postgres服务 cmd命令 services.msc找到服务停止 二.修改注册表 cmd命令 regedit找到路径 \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\postgresql-x64-13 将“&#xff0d;D”后的目录名修改为新的数据目录位置即可&#xff0c;如果目录路径中含有…

【C++】泛型编程 ⑦ ( 类模板常用用法 | 类模板声明 | 类模板调用 | 类模板作为函数参数 )

文章目录 一、类模板基础用法1、类模板声明定义2、类模板使用3、类模板做函数参数 二、完整代码示例1、代码示例2、执行结果 一、类模板基础用法 1、类模板声明定义 上一篇博客中 , 【C】泛型编程 ⑥ ( 类模板 | 类模板语法 | 代码示例 ) 讲解了模板类的基础语法 , 模板类声明如…

23 - 如何优化JVM内存分配?

JVM 调优是一个系统而又复杂的过程&#xff0c;但我们知道&#xff0c;在大多数情况下&#xff0c;我们基本不用去调整 JVM 内存分配&#xff0c;因为一些初始化的参数已经可以保证应用服务正常稳定地工作了。 但所有的调优都是有目标性的&#xff0c;JVM 内存分配调优也一样。…

计算机网络的标准化工作及相关组织

一、国际化组织 计算机网络的标准化工作由一些主要的组织来进行管理和推动。以下是几个主要的计算机网络标准化的国际组织及其相关的标准&#xff1a; 1. 国际标准化组织&#xff08;ISO&#xff09;&#xff1a;国际标准化组织负责制定各种行业的标准&#xff0c;包括计算机…

Linux性能分析——TOP命令详解

我的圈子&#xff1a; 高级工程师聚集地 我是董哥&#xff0c;高级嵌入式软件开发工程师&#xff0c;从事嵌入式Linux驱动开发和系统开发&#xff0c;曾就职于世界500强公司&#xff01; 创作理念&#xff1a;专注分享高质量嵌入式文章&#xff0c;让大家读有所得&#xff01; …

网络割接用VRRP替换HSRP

如图3-11所示&#xff0c;C6500作为核心层设备上行连接出口路由器NE40E-X3&#xff0c;下行连接接入层设备CE6800。C6500上配置HSRP实现冗余备份网关&#xff0c;同时在二层网络部署MSTP破除环路。 总体思路 HSRP为CISCO私有协议&#xff0c;CE系列交换机&#xff08;以CE1280…

基于go标准分层架构项目设计实现

基于go标准分层架构项目设计实现 缘起 个人博客网址 最近主要看了两方面知识&#xff0c;一方面是技术相关的&#xff0c;如何设计一个比较好的后端架构项目代码&#xff1b;一方面是非技术相关的&#xff0c;如何写一篇好的技术文章&#xff0c;能够让他人读懂并有收获。因…

C++ 形参传值和传指针的误解

#include <stdio.h>void swap(int *x, int *y);main(){ int a 5, b 9;int *pp &a;int *kk &b;swap(pp, kk);printf("a%d\nb%d\n", *pp, *kk);return 0; } void swap(int *x, int *y) {int *t;t x;x y;y t; } 会发现&#xff0c;输出结果并没有…

iptables详解:常用模块的基本使用

目录 tcp扩展模块 multiport扩展模块 iprange扩展模块 connlimit模块 limit扩展模块 udp扩展模块 icmp扩展模块 state扩展模块 限制每分钟接收10个ICMP数据报文 允许10个数据报文快速通过&#xff0c;然后限制每分钟接收1个个ICMP数据报文 限制网络传输的带宽不可以…