Redis-基础篇

Redis是一个开源、高性能、内存键值存储数据库,由 Salvatore Sanfilippo(网名antirez)创建,并在BSD许可下发布。它不仅可以用作缓存系统来加速数据访问,还可以作为持久化的主数据存储系统或消息中间件使用。Redis因其数据结构丰富、性能优异和高可用性而被广泛应用在现代分布式架构中。

目录

一、认识Redis

1.1、认识NoSQL

1.2、认识Redis

1.3、安装Redis

二、Redis的常见命令

2.1、5种常见的数据结构

2.2、通用命令

2.3、不同数据结构的操作命令

三、Redis的Java客户端

3.1、Jedis客户端

3.2、SpringDataRedis客户端


一、认识Redis

1.1、认识NoSQL

SQL:结构化、表有关联、支持SQL查询、满足事务的ACID、存储在磁盘、垂直扩展、适用于数据结构固定,相关业务的数据安全性与一致性要求高的场合

NoSQL:非结构、无关联的、非SQL、满足基本一致性、存储在内存、水平扩展、适用于数据结构不固定,对一致性与安全性要求不高,但是对性能要求较高的场合

常见的NoSQL有:键值对类型的Redis、文档类型的MongoDB

1.2、认识Redis

Redis( Remote Dictionary Server)的全程是远程字典服务器,是一个基于内存的非关系型数据库。

redis的特征:
1.键值对类型的数据库,支持丰富的数据类型

2.单线程,每个命令具备原子性

3.低延迟,速度快(基于内存、IO多路复用、良好的编码)

4.支持数据的持久化

5.支持主从集群与分片集群

6.支持多语言客户端

1.3、安装Redis

这个不过多介绍,直接下载安装即可。

安装redis服务器和客户端,并安装redis可视化管理工具Another Redis Desktop Manager。

二、Redis的常见命令

2.1、5种常见的数据结构

redis是一个键值对类型的数据库,key的类型一般是String,value的类型就多种多样:

基本数据类型:

String类型:缓存用户信息、计数器(例如点赞数、浏览量)、简单的键值对存储等。

Hash类型:存储用户属性集合(如用户的姓名、年龄、地址等)、产品详情等多字段数据结构。

List类型:存储用户属性集合(如用户的姓名、年龄、地址等)、产品详情等多字段数据结构。

Set类型:适用于标签系统(给一篇文章打上多个标签)、唯一事件记录等。

SortedSet类型:跳跃表提供O(log N)级别的插入、删除和查找操作,并按分数排序。

特殊数据类型:

GEO类型:Geo数据类型允许用户存储地理位置信息,并执行地理半径查询、邻近点搜索等操作。

BitMap类型:用于用户在线状态跟踪、访问统计(例如用户是否读过某篇文章)。

HyperLog类型:日活用户统计、网站独立访客统计、广告点击去重等需要估算大量唯一元素数量而不需精确存储所有元素的场景。

2.2、通用命令

通用命令常见的有:

KEYS:查看符合模板的所有key,不建议在生产环境上使用

DEL:删除一个指定的key

EXISTS:判断一个key是否存在

EXPIRE:为一个key设置有效期,有效期到了key会自动删除

TTL:查看key的剩余有效期

2.3、不同数据结构的操作命令

String类型:字符串类型,包括普通字符串,整数,浮点数

API如下:

SET:添加或者修改string类型的键值对

GET:根据key获取string类型的value

MSET:批量添加多个string类型的键值对

MGET:根据string类型的key获取多个string类型的值

INCR:让整型的key自增1

INCREBY:整数设置步长的自增

INCREBYFLOAT:按照指定步长的浮点型自增

SETNX:添加一个string类型的键值对,前提是key不存在,否则不执行

SETEX:添加一个string类型的键值对,并指定有效期

redis的key允许有多个单词形成层级结构,多个单词用“:”隔开,如果value是一个Java对象,则可以将对象序列化成JSON字符串后存储:
例如key可以为  项目名:业务名:类型:id      value为{“id”:1,"product":"小米手机","price":"2999"}

这样redis会根据冒号:进行层级划分。

Hash类型:也称为散列,value是一个无序字典,类似于Java中的HashMap结构。之前的string类型的value是将对象序列化成JSON字符串后存储,当需要修改某个字段时很不方便。

Hash结构可以将每个字段独立存储,可以针对每个字段进行操作。

相关的API:

HSET key field value:添加或者修改hash类型的key的field值

HGET key field:获取一个hash类型的key的field值

HMSET:批量添加多个hash类型key的field值

HMGET:批量查询多个hash类型key的field值

HGETALL:获取一个hash类型key的所有feild的值

HKEYS:获取一个hash类型的key中的所有feild

HVALS:获取一个hash类型的key中的所有value

HINCREBY:让hash类型的key自增并指定步长

HSETNX:添加一个hash类型的field,前提是field不存在,否则不执行

List类型:List类型与Java中的LinkedList类似,可以看作是一个双向链表,支持正向与反向检索。

特征:有序、允许元素重复、插入删除快、查询速度一般

List的常见命令如下:

LPUSH key element...:向列表左侧插入一个或者多个元素

LPOP key :移除并返回列表左侧额第一个元素,没有则返回nil

RPUSH key element...:向列表右侧插入一个或者多个元素

RPOP key:移除并返回列表右侧的第一个元素

LRANGE key  start end:返回一段角标范围内的所有元素

BLPOP与BRPOP:移除指定的元素,没有元素时并设置等待时间,而不是直接返回nil

List模拟栈:lpush与lpop  rpush与rpop

List模拟队列:lpush与rpop

List模拟阻塞队列:blpop与brpop

Set类型:Redis中的set与Java中的HashSet类似,具有如下特征:无序、元素不可重复、查找快

、支持交集、并集差集等操作。

SET类型的常见命令:

SADD key member...:向set中添加一个或者多个元素

SREM key member...:向set中移除指定元素

SCARD key:返回set中的元素个数

SISMEMBER key member:判断一个元素是否在set中

SMEMBERS:获取set中的所有元素

SINTER key1 key2:求两个key的交集

SDIFF:求两个集合的差集

SUNION:求两个集合的并集

SortedSet类型:有序的集合,每个元素都带有一个score属性,可以根据score属性进行排序,底层是一个跳表+hash表的实现。跳跃表提供O(log N)级别的插入、删除和查找操作,并按分数排序;hash表用于快速查找成员的存在性。

跳表是通过随机函数维护平衡性的,当我们在跳表中插入数据的时候,我们通过选择同时将这个数据插入到部分索引层中,如何选择索引层,可以通过一个随机函数来决定这个节点插入到哪几级索引中,比如随机生成了k,那么就将这个索引加入到,第一级到第k级索引中。

SortedSet具有以下特点:

1、可排序 2、元素不重复 3、查询速度快

常见的SortedSort的api如下:默认是升序,如果向降序前缀由Z改成ZREV

三、Redis的Java客户端

3.1、Jedis客户端

常见的Redis的Java客户端有Jedis、Lettuce、Redisson三种,具体如下。

下面我们通过jedis客户端连接redis服务器,并进行单元测试,具体如下:

1.首先添加三方依赖。

    <!--jedis客户端依赖-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.7.0</version>
        </dependency>

        <!-- junit测试依赖 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.7.0</version>
            <scope>test</scope>
        </dependency>

2.编写单元测试模块,jedis客户端连接redis服务器,并进行crud基本操作,最后释放连接。

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

/**
 * @author nuist__NJUPT
 * @ClassName JedisTest
 * @description: jedis测试类
 * @date 2024/03/02
 */
public class JedisTest {

    private Jedis jedis ;

    @BeforeEach
    void setUp(){
        // 1.建立连接
        jedis = new Jedis("localhost", 6379) ;
        // 2.设置密码
        jedis.auth("123456") ;
        // 3.选择库
        jedis.select(0) ;
    }

    @Test
    void testString(){

        // 存入数据
        String result = jedis.set("name", "mandy");
        System.out.println(result);
        // 获取数据
        String name = jedis.get("name");
        System.out.println("name : " + name );

    }

    @Test
    void testHash(){
        // 存值
        jedis.hset("user:1", "name", "jack") ;
        jedis.hset("user:1", "age", "21") ;
        // 取值
        Map<String, String> stringStringMap = jedis.hgetAll("user:1");
        System.out.println(stringStringMap);

    }

    @AfterEach
    void tearDown(){
        if(jedis != null){
            jedis.close();
        }
    }

}

jedis本身是线程不安全的,而且频繁的创建与销毁jedis连接会有性能损耗,因此推荐使用jedis连接池的方式代替直连的方式。

1.定义一个连接池工具类,用于建立jedis连接,并返回jedis对象,jedis使用完放回连接池而不是直接销毁。

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author nuist__NJUPT
 * @ClassName JedisConnectionFactory
 * @description: Jedis连接池
 * @date 2024/03/02
 */
public class JedisConnectionFactory {

    private static final JedisPool jedisPool ;

    static {
        // 配置连接池
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(8);
        jedisPoolConfig.setMaxIdle(8);
        jedisPoolConfig.setMinIdle(0);
        jedisPoolConfig.setMaxWaitMillis(1000);

        // 创建连接池对象
        jedisPool= new JedisPool(jedisPoolConfig, "localhost", 6379, 1000, "123456");
    }

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

}

2.客户端直接通过连接池获取jedis对象就可以,不用直接newjedis对象进行直连了。

import com.alibaba.jedis.util.JedisConnectionFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;

import java.util.Map;

/**
 * @author nuist__NJUPT
 * @ClassName JedisTest
 * @description: jedis测试类
 * @date 2024/03/02
 */
public class JedisTest {

    private Jedis jedis ;

    @BeforeEach
    void setUp(){
        // 1.建立连接
        // jedis = new Jedis("localhost", 6379) ;
        jedis = JedisConnectionFactory.getJedis() ;
        // 2.设置密码
        jedis.auth("123456") ;
        // 3.选择库
        jedis.select(0) ;
    }

    @Test
    void testString(){

        // 存入数据
        String result = jedis.set("name", "mandy");
        System.out.println(result);
        // 获取数据
        String name = jedis.get("name");
        System.out.println("name : " + name );

    }

    @Test
    void testHash(){
        // 存值
        jedis.hset("user:1", "name", "jack") ;
        jedis.hset("user:1", "age", "21") ;
        // 取值
        Map<String, String> stringStringMap = jedis.hgetAll("user:1");
        System.out.println(stringStringMap);

    }

    @AfterEach
    void tearDown(){
        if(jedis != null){
            jedis.close();
        }
    }

}

3.2、SpringDataRedis客户端

SpringData是Spring中数据操作的模块,包含了对多种数据库的集成,其中对redis的集成就是SpringDataRedis。它提供了对不同redis客户端的整合(jedis、Lettuce),提供了RedisTemplate统一API来操作Redis,支持redis的发布订阅模型,支持redis哨兵和redis集群,支持基于Lettuce的响应式编程,支持序列化与反序列化。

下面看一下SpringDataRedis提供的工具类RedisTemplate的应用,首先创建springboot项目并导入redis依赖。

  <!--	jackson依赖	-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.5</version>
        </dependency>

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

        <!-- 连接池依赖 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

然后在yml文件中进行配值,配值redis的数据源信息。

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100

编写redisTemplate的配值类,防止在redis在接收Object类型时,把Object对象序列化成字节形式,变成一串乱码,可读性差,占用内存。


/**
 * @author nuist__NJUPT
 * @ClassName RedisConfig
 * @description: redis配置类
 * @date 2024/03/02
 */


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

@Configuration
public class RedisConfig {

    /**
     * RedisTemplate可以接收任意Object作为值写入Redis,
     * 只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的一串很长的值
     * 缺点:可读性查、浪费存储空间
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        // 1.创建 redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 2.设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 3.设置序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // key 采用 String 序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        // value 采用 json 序列化
        redisTemplate.setValueSerializer(jsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jsonRedisSerializer);

        return  redisTemplate;

    }
}

定义一个实体类。

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author nuist__NJUPT
 * @ClassName User
 * @description: 实体类
 * @date 2024/03/02
 */

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private String name ;
    private Integer age ;

}

最后编写单元测试模块,利用redisTemplate进行测试。

import com.alibaba.redisdemo.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class RedisDemoApplicationTests {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Test
    void testString(){

        // 添加一个元素
        redisTemplate.opsForValue().set("name", "Jack");
        // 获取元素
        Object object = redisTemplate.opsForValue().get("name");
        System.out.println(object);
    }

    @Test
    void testSaveUser(){
        //写入数据
        redisTemplate.opsForValue().set("user:2", new User("wang", 18));
        // 读取数据
        User user = (User) redisTemplate.opsForValue().get("user:2");
        System.out.println(user);
    }
  @Test
    void testHash(){

        stringRedisTemplate.opsForHash().put("user:3","name", "liu");
        stringRedisTemplate.opsForHash().put("user:3","age","18") ;

        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:3");
        System.out.println("entries = " + entries);

    }

}

上述尽管Json序列化的方式满足要求,但是会发现仍然存在一些问题,比如JSON序列化器将类型class写入了json中,存入redis会导致额外的内存开销。

为了节省内存空间,不使用JSON序列化来处理value,而是处理String序列化器,要求只能存储String类型的key与value,当存储Java对象的时候需要手动的序列化与反序列化。

可以采用如下写法:
 

 @Autowired
    private StringRedisTemplate stringRedisTemplate ;

    private static final ObjectMapper mapper = new ObjectMapper() ;
    @Test
    void testSave() throws JsonProcessingException {
        // 创建对象
        User user = new User("wang", 18);
        // 手动序列化
        String s = mapper.writeValueAsString(user);
        //写入数据
        stringRedisTemplate.opsForValue().set("user:2",s);
        // 读取数据
        String user1 = stringRedisTemplate.opsForValue().get("user:2");
        // s手动反序列化
        User user2 = mapper.readValue(user1, User.class);

        System.out.println(user2);
    }

使用fastJson进行序列化与反序列化也可以,需要添加依赖。

    @Autowired
    private StringRedisTemplate stringRedisTemplate ;

    @Test
    void testSave() throws JsonProcessingException {
        // 创建对象
        User user = new User("wang", 19);
        // 手动序列化
        String s = JSON.toJSONString(user) ;
        //写入数据
        stringRedisTemplate.opsForValue().set("user:2",s);
        // 读取数据
        String user1 = stringRedisTemplate.opsForValue().get("user:2");
        // s手动反序列化
        User user2 = JSON.parseObject(user1, User.class) ;

        System.out.println(user2);
    }

添加fastJson依赖。

<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.32</version>
</dependency>

总结:redis中有两种序列化方式,推荐使用第二种。

1.第一种是自定义RedisTemplate,修改其序列化器,相对方便,但是写入redis会存class对象,占用额外的内存空间。

2.使用StringRedisTemplate,默认使用String序列化器,写入redis需要将Java对象手动序列化为json,读取redis需要将读取到的json反序列化为Java对象。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大数据架构(3)】Lambda vs. Kappa Architecture-选择你需要的架构

文章目录 一. Data Processing Architectures1. Lambda Architecture1.1. 架构说明a. Data Ingestion Layerb. Batch Layer (Batch processing)c. Speed Layer (Real-Time Data Processing)d. Serving Layer 1.2. Lambda Architecture的优缺点1.3. 使用案例 2. Kappa Architect…

数据分析-Pandas数据的探查面积图

数据分析-Pandas数据的探查面积图 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&…

MyBatis 面试题

什么是MyBatis&#xff1f; MyBatis 是一个开源、轻量级的数据持久化框架&#xff0c;是 JDBC 和 Hibernate 的替代方案。MyBatis 内部封装了 JDBC&#xff0c;简化了加载驱动、创建连接、创建 statement 等繁杂的过程&#xff0c;开发者只需要关注 SQL 语句本身。 MyBatis 支…

静态时序分析:SDC约束命令set_case_analysis详解

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 目录 指定值 指定端口/引脚列表 简单使用 set_case_analysis命令用于对电路进行特定模式的设定&#xff0c;例如对于一个工作在正常模式下的芯片&#xff0c;…

08 yum和git

什么是软件包 安装软件&#xff0c;一个通常的办法就是下载程序的源代码进行编译。这种太麻烦&#xff0c;于是一些人把常用软件编译好&#xff0c;做成软件包放在服务器上&#xff0c;通过包管理器可以很方便的得到这个软件包安装&#xff0c;就好比手机上的应用商店 yum&am…

美梦从舒适开始,康姿百德床垫为睡眠健康护航

在当今社会&#xff0c;高质量的睡眠已成为人们对生活品质的追求&#xff0c;对床垫的选择也变得越来越讲究。在我们繁忙的生活中&#xff0c;一张优质的床垫不仅是我们舒适休息的保障&#xff0c;更是保持健康生活方式的重要部分。康姿百德床垫&#xff0c;作为市场上的佼佼者…

14-Linux部署Hadoop集群

Linux部署Hadoop集群 简介 1&#xff09;Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 2&#xff09;主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。 Hadoop HDFS 提供分布式海量数据存储能力 Hadoop YARN 提供分布式集群资源管理能力 Hadoop…

R语言使用dietaryindex包计算NHANES数据多种健康饮食指数 (HEI等)(1)

健康饮食指数 (HEI) 是评估一组食物是否符合美国人膳食指南 (DGA) 的指标。Dietindex包提供用户友好的简化方法&#xff0c;将饮食摄入数据标准化为基于指数的饮食模式&#xff0c;从而能够评估流行病学和临床研究中对这些模式的遵守情况&#xff0c;从而促进精准营养。 该软件…

【C++】string 类 ( 上)

标准库中的string类 注意&#xff1a; 1. string是表示字符串的字符串类 2. 该类的接口与常规容器的接口基本相同&#xff0c;再添加了一些专门用来操作string的常规操作。 比特就业课 3. string在底层实际是&#xff1a;basic_string模板类的别名&#xff0c;typedef basi…

RFID(Radio Frequency Identification)技术笔记

一、RFID的介绍 RFID&#xff0c;全称为Radio Frequency Identification&#xff0c;即射频识别技术&#xff0c;也常被称为电子标签或无线射频识别。它是一种非接触式的自动识别技术&#xff0c;通过射频信号自动识别目标对象并获取相关数据&#xff0c;识别过程无需人工干预&…

LeetCode 刷题 [C++] 第45题.跳跃游戏 II

题目描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i]i j < n 返回到达 nums[n …

金融行业专题|期货超融合架构转型与场景探索合集(2023版)

更新内容&#xff1a; 更新 SmartX 超融合在期货行业的覆盖范围、部署规模与应用场景。新增 CTP 主席系统实践与评测、容器云资源池等场景实践。更多超融合金融核心生产业务场景实践&#xff0c;欢迎下载阅读电子书《SmartX 金融核心生产业务场景探索文章合集》。 面对不断变…

【AI Agent系列】【MetaGPT多智能体学习】6. 多智能体实战 - 基于MetaGPT实现游戏【你说我猜】(附完整代码)

本系列文章跟随《MetaGPT多智能体课程》&#xff08;https://github.com/datawhalechina/hugging-multi-agent&#xff09;&#xff0c;深入理解并实践多智能体系统的开发。 本文为该课程的第四章&#xff08;多智能体开发&#xff09;的第四篇笔记。今天我们来完成第四章的作…

深度学习需要掌握哪些数学基础?

《深度学习的数学》这本书再合适不过了。作者罗纳德.T.纽塞尔&#xff08;Ronald T. Kneusel&#xff09;&#xff0c;拥有超过 20年的机器学习行业经验。 本书适合有一定深度学习基础、了解Python编程语言的读者阅读&#xff0c;也可作为用于拓展深度学习理论的参考书。 为什么…

SQL 术语:Join 中的 Build 和 Probe 是什么意思?

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

vue+springboot项目部署服务器

项目仓库&#xff1a;vuespringboot-demo: vuespringboot增删改查的demo (gitee.com) ①vue中修改配置 在public文件夹下新建config.json文件&#xff1a; {"serverUrl": "http://localhost:9090"//这里localhost在打包后记得修改为服务器公网ip } 然后…

Linux: Network: socket: sendto 如果返回0,是否一定代表发送成功?

最近遇到一个问题&#xff0c;虽然应用层使用的系统调用send已经返回成功&#xff0c;而且没有错误日志产生&#xff0c;也没有errno的设置。那是不是代表一定是没有问题&#xff1f;从抓包的结果看&#xff0c;虽然上层应用已经显示发出去&#xff0c;但是实际抓包的时候&…

WP外贸营销型网站模板

WordPress外贸独立站主题 简洁实用的WordPress外贸独立站主题&#xff0c;适合时尚服装行业搭建wordpress企业官网使用。 零件配件WordPress外贸建站模板 汽车行业零配件WordPress外贸建站模板&#xff0c;卖配件、零件的外贸公司可以使用的WordPress主题。 https://www.jia…

windows 系统上搭建 Phpstudy 集成环境 + DVWA 靶场!超详细教程!

作为安全测试或渗透测试学习者&#xff0c;需要搭建一些靶场来进行技术练习&#xff0c;靶场类型有很多&#xff0c;搭建方式也支持多样&#xff0c;本文给你详细介绍windows系统下如何通过phpstudy集成环境搭建DVWA靶场&#xff01; 一、前言 网站是由中间件、网站程序、数据库…

暗九之凶险,更甚于明九

俗话说“逢九必衰”&#xff0c;逢九年是人运程变化的一个过程&#xff0c;这是古人长期以来对于命运的一种总结。“九”是转弯之数&#xff0c;故 “逢九”之人当年的运程容易大起大落、易招变数&#xff0c;若是严重一些&#xff0c;则有可能会殒命在这一年&#xff0c;一定要…