Springboot-redis整合

Springboot-redis命令行封装


前言

Redis(Remote Dictionary Server),即远程字典服务,是一个开源的使用ANSI C语言编写的、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis也是现在最受欢迎的NoSQL数据库之一,其中的NoSQL是“Not Only SQL”的缩写,泛指非关系型数据库。

redis的常用使用场景,可以做缓存,分布式锁,自增序列等,使用redis的方式和我们使用数据库的方式差不多,首先我们要在自己的本机电脑或者服务器上安装一个redis的服务器,通过我们的java客户端在程序中进行集成,然后通过客户端完成对redis的增删改查操作。redis的Java客户端类型还是很多的,常见的有jedis, redission,lettuce等,所以我们在集成的时候,我们可以选择直接集成这些原生客户端。但是在springBoot中更常见的方式是集成spring-data-redis,这是spring提供的一个专门用来操作redis的项目,封装了对redis的常用操作,里边主要封装了jedis和lettuce两个客户端。相当于是在他们的基础上加了一层门面。

本篇文章我们就来重点介绍,springBoot通过集成spring-data-redis使用对于redis的常用操作。


本篇博客SpringBoot版本为2.6.13,请注意版本兼容问题

SpringBoot配置redis

一、pom文件中引入redis依赖
<!--        redis--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

直接引入上述依赖后,点进去会发现,里面包含了spring-data-redis和 lettuce-core两个核心包,这就是为什么说我们的spring-boot-starter-data-redis默认使用的就是lettuce这个客户端了。

如果我们想要使用jedis客户端怎么办呢?就需要排除lettuce这个依赖,再引入jedis的相关依赖就可以了。

请添加图片描述

那么为什么我们只需要通过引入不同的依赖就能让spring-data-redis可以自由切换客户端呢,这其实就涉及到了springBoot的自动化配置原理,为大家简述一下。

springBoot这个框架之所以可以通过各种starter无缝融合其他技术的一大主要原因就是springBoot本身的自动化配置功能。所谓自动化配置就是springBoot本身已经预先设置好了一些常用框架的整合类。然后通过类似于ConditionOn这样的条件判断注解,去辨别你的项目中是否有相关的类(或配置)了,进而进行相关配置的初始化。

springBoot预设的自动化配置类都位于spring-boot-autoconfigure这个包中,只要我们搭建了springBoot的项目,这个包就会被引入进来。

请添加图片描述

这个包下就有一个RedisAutoConfiguration这个类,顾名思义就是Redis的自动化配置。在这个类中,会引入LettuceConnectionConfiguration 和 JedisConnectionConfiguration 两个配置类,分别对应lettuce和jedis两个客户端。

请添加图片描述

LettuceConnectionConfiguration配置类中,通过@ConditionalOnClass 和 ConditionalOnProperty进行条件判断,是否允许自动装配。

@ConditionalOnClass({RedisClient.class});只有当RedisClient这个类在类路径上可用时,带有这个注解的bean或配置才会被创建。换句话说,如果RedisClient类不存在于类路径中(例如,你没有包含相关的依赖),那么任何使用这个注解的bean或配置都不会被Spring Boot创建或应用。

在Spring Boot Data Redis的上下文中,RedisClient类是Lettuce连接工厂的一个关键部分,因此这个条件确保只有在Lettuce客户端库可用时,相关的自动配置才会生效。

@ConditionalOnProperty()允许你基于application.propertiesapplication.yml文件中的属性来决定是否创建bean。只有当application.propertiesapplication.yml文件中有一个属性spring.redis.lettuce.enabled并且它的值为true时,带有这个注解的bean或配置才会被创建。

请添加图片描述

JedisConnectionConfiguration 中也通过类似的条件判断注解进行判定是否自动装配

请添加图片描述

由于我们的项目通过redis starter 自动引入了lettuce-core,而没有引入jedis相关依赖,所以LettuceConnectionConfiguration这个类的判断成立会被加载,而Jedis的判断不成立,所以不会加载。进而lettuce的配置生效,所以我们在使用的使用, 默认就是lettuce的客户端。

二、yml文件中进行基本的配置
spring:redis:host: localhostpassword:   #your passwordport: 6379database: 0 #default database 0#连接池lettuce:pool:max-active: 8 #最大连接池max-idle: 4 #连接池中的最大空闲连接min-idle: 2 #连接池中的最小空闲连接

但是有的时候我们想要给我们的redis客户端配置上连接池。就像我们连接mysql的时候,也会配置连接池一样,目的就是增加对于数据连接的管理,提升访问的效率,也保证了对资源的合理利用。那么我们如何配置连接池呢,这里大家一定要注意了,很多网上的文章中,介绍的方法可能由于版本太低,都不是特别的准确。 比如很多人使用spring.redis.pool来配置,这个是不对的(不清楚是不是老版本是这样的配置的,但是在springboot-starter-data-redis中这种写法不对)。首先是配置文件,由于我们使用的lettuce客户端,所以配置的时候,在spring.redis下加上lettuce再加上pool来配置。

此外连接池配置还需要加入一个依赖

 <!--        对象池依赖--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
三、项目中使用

我们的配置工作准备就绪以后,我们就可以在项目中操作redis了,操作的话,使用spring-data-redis中为我们提供的 RedisTemplate 这个类,就可以操作了。我们先举个简单的例子,插入一个键值对(值为string)

@RestController
@RequestMapping("/redis")
public class BasicController {@Autowiredprivate RedisTemplate redisTemplate;@GetMapping("save")public String save(String key, String value) {redisTemplate.opsForValue().set(key, value);return "ok";}
}

但是运行之后发送请求,在成功存储后,通过命令查看redis 数据库0,获取keys的时候,会发现一个比较难受的东西,我们发现存进去的key明明是"a",但是查询得到的key确是这么一段玩意儿,而且通过它获取value也不会获取成功。

“\xac\xed\x00\x05t\x00\x01a”

问题出在了这里:

当你在Spring Boot中使用redisTemplate.opsForValue().set(a, 1);来设置一个值到Redis时,实际上你存储的是一个序列化后的对象。默认情况下,Spring Boot中的RedisTemplate使用Java序列化来存储对象。

当你从Redis命令行工具执行keys *命令时,你看到的是序列化后的数据的二进制表示。这就是为什么你看到\xac\xed\x00\x05t\x00\x01a这样的输出,这是Java对象序列化后的字节表示。

如果你希望在Redis命令行中看到更友好的数据表示,你可以考虑以下几种方法:

  1. 使用字符串表示
    如果你只是存储简单的字符串或数字,你可以直接使用StringRedisTemplate而不是RedisTemplate。这样,数据就不会被序列化,而是直接以字符串形式存储。
  2. 自定义序列化器
    你可以为RedisTemplate配置自定义的序列化器,例如使用JSON序列化器。这样,存储的数据将是JSON格式的,你可以在命令行中更容易地查看。
  3. 反序列化数据
    如果你确实需要查看或操作存储在Redis中的数据,你可以从Spring Boot应用中读取它,并反序列化回原始对象。

那就自定义一下序列化叭

package com.jerry.springbootredis.conf;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @version 1.0* @Author jerryLau* @Date 2024/4/8 14:32* @注释*/
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {// 创建RedisTemplate<String, Object>对象RedisTemplate<String, Object> template = new RedisTemplate<>();// 配置连接工厂template.setConnectionFactory(connectionFactory);// 定义Jackson2JsonRedisSerializer序列化对象Jackson2JsonRedisSerializer<Object> jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jacksonSeial.setObjectMapper(om);StringRedisSerializer stringSerial = new StringRedisSerializer();// redis key 序列化方式使用stringSerialtemplate.setKeySerializer(stringSerial);// redis value 序列化方式使用jacksontemplate.setValueSerializer(jacksonSeial);// redis hash key 序列化方式使用stringSerialtemplate.setHashKeySerializer(stringSerial);// redis hash value 序列化方式使用jacksontemplate.setHashValueSerializer(jacksonSeial);template.afterPropertiesSet();return template;}
}

再次通过api接口保存(“a”,“b”),通过可视化工具查看,获得a的值为”b“

请添加图片描述

四、工具类封装

我们在前面的代码中已经通过RedisTemplate成功操作了redis服务器,比如set一个字符串,我们可以使用:

redisTemplate.opsForValue().set(key, value);

来put一个String类型的键值对。而redis中可以支持 string, list, hash,set, zset五种数据格式,这五种数据格式的常用操作,都在RedisTemplate这个类中进行了封装。 操作string类型就是用opsForValue,操作list类型是用listOps, 操作set类型是用setOps等等。

尝试通过自定义工具类的方式进行一些操作的封装,在之后的操作中可以直接注入工具类,进行使用

封装:
package com.jerry.springbootredis.utils;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** @version 1.0* @Author jerryLau* @Date 2024/4/8 14:42* @注释 封装redis 操作命令*/
@Component
public class RedisUtils {@Autowiredprivate RedisTemplate redisTemplate;/**** 为键所对应的值设置过期时间* @param key* @param timeout 毫秒数* @return*/public boolean expire(String key, long timeout) {return redisTemplate.expire(key, timeout, TimeUnit.MILLISECONDS);}/**** 根据key 获取键值对过期时间* @param key* @return*/public long getValueTimeOut(String key) {return redisTemplate.getExpire(key);}/**** 查找是否包含某个键* @param key* @return*/public boolean hasKey(String key) {return redisTemplate.hasKey(key);}/**** 移除指定某个key的时间* @param key* @return*/public boolean persist(String key) {return redisTemplate.boundValueOps(key).persist();}//------------------String 操作--------------/**** 按照key值取* @param key* @return*/public Object get(String key) {return key.isEmpty() ? null : redisTemplate.opsForValue().get(key);}/**** 按照key进行存* @param key* @param value*/public void set(String key, String value) {redisTemplate.opsForValue().set(key, value);}/**** 按照key设置过期时间存* @param key* @param value* @param timeOut ms*/public void set(String key, String value, Long timeOut) {if (timeOut > 0) {redisTemplate.opsForValue().set(key, value, timeOut, TimeUnit.MILLISECONDS);} else {redisTemplate.opsForValue().set(key, value);}}/*** 批量添加 key (重复的键会覆盖)** @param keyAndValue*/public void batchSet(Map<String, String> keyAndValue) {redisTemplate.opsForValue().multiSet(keyAndValue);}/*** 批量添加 key-value 只有在键不存在时,才添加* map 中只要有一个key存在,则全部不添加** @param keyAndValue*/public void batchSetIfAbsent(Map<String, String> keyAndValue) {redisTemplate.opsForValue().multiSetIfAbsent(keyAndValue);}/*** 对一个 key-value 的值进行加减操作,* 如果该 key 不存在 将创建一个key 并赋值该 number* 如果 key 存在,但 value 不是长整型 ,将报错** @param key* @param number*/public Long increment(String key, long number) {return redisTemplate.opsForValue().increment(key, number);}/*** 对一个 key-value 的值进行加减操作,* 如果该 key 不存在 将创建一个key 并赋值该 number* 如果 key 存在,但 value 不是 纯数字 ,将报错** @param key* @param number*/public Double increment(String key, double number) {return redisTemplate.opsForValue().increment(key, number);}//------------------无序集合 set类型 操作--------------/*** 将数据放入set缓存** @param key 键* @return*/public void sSet(String key, String value) {redisTemplate.opsForSet().add(key, value);}/*** 获取变量中的值** @param key 键* @return*/public Set<Object> members(String key) {return redisTemplate.opsForSet().members(key);}/*** 随机获取set中key变量中指定个数的value** @param key   键* @param count 个数* @return key=key key对应的value值中随机取count个返回*/public List randomMembers(String key, long count) {return redisTemplate.opsForSet().randomMembers(key, count);}/*** 随机获取变量中的元素** @param key 键* @return key=key key对应的value值中随机取1个返回*/public Object randomMember(String key) {return redisTemplate.opsForSet().randomMember(key);}/*** 弹出无序列表中的元素* 全部弹出后列表会被删除,继续弹出会报错空指针* @param key 键* @return*/public Object pop(String key) {return redisTemplate.opsForSet().pop(key);}/*** 获取变量中值的长度** @param key 键* @return*/public long size(String key) {return redisTemplate.opsForSet().size(key);}/*** 根据value从一个set中查询,是否存在** @param key   键* @param value 值* @return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {return redisTemplate.opsForSet().isMember(key, value);}/*** 检查给定的元素是否在变量中。** @param key 键* @param obj 元素对象* @return*/public boolean isMember(String key, Object obj) {return redisTemplate.opsForSet().isMember(key, obj);}/*** 转移变量的元素值到目的变量。** @param key     键* @param value   元素对象* @param destKey 元素对象* @return*/public boolean move(String key, String value, String destKey) {return redisTemplate.opsForSet().move(key, value, destKey);}/*** 批量移除set缓存中元素** @param key    键* @param values 值* @return*/public void remove(String key, Object... values) {redisTemplate.opsForSet().remove(key, values);}/*** 通过给定的key求2个set变量的差值** @param key     键* @param destKey 键* @return*/public Set<Set> difference(String key, String destKey) {return redisTemplate.opsForSet().difference(key, destKey);}------------------hash类型 操作--------------/*** 加入缓存** @param key 键* @param map 键* @return*/public void add(String key, Map<String, String> map) {redisTemplate.opsForHash().putAll(key, map);}/*** 获取 key 下的 所有  hashkey 和 value** @param key 键* @return*/public Map<Object, Object> getHashEntries(String key) {return redisTemplate.opsForHash().entries(key);}/*** 验证指定 key 下 有没有指定的 hashkey** @param key* @param hashKey* @return*/public boolean hashKey(String key, String hashKey) {return redisTemplate.opsForHash().hasKey(key, hashKey);}/*** 获取指定key的值string** @param key  redis的键* @param key2 存储数据map的键* @return*/public String getMapString(String key, String key2) {return redisTemplate.opsForHash().get(key, key2).toString();}/*** 获取指定的值Int** @param key  redis的键* @param key2 存储数据map的键* @return map中可以转化为int的value值*/public Integer getMapInt(String key, String key2) {return Integer.valueOf( redisTemplate.opsForHash().get(key, key2).toString());}/*** 弹出元素并删除** @param key 键* @return*/public String popValue(String key) {return redisTemplate.opsForSet().pop(key).toString();}/*** 删除指定 hash 的 HashKey** @param key* @param hashKeys* @return 删除成功的 数量*/public Long delete(String key, String... hashKeys) {return redisTemplate.opsForHash().delete(key, hashKeys);}/*** 给指定 hash 的 hashkey 做增减操作** @param key* @param hashKey* @param number* @return*/public Long increment(String key, String hashKey, long number) {return redisTemplate.opsForHash().increment(key, hashKey, number);}/*** 给指定 hash 的 hashkey 做增减操作** @param key* @param hashKey* @param number* @return*/public Double increment(String key, String hashKey, Double number) {return redisTemplate.opsForHash().increment(key, hashKey, number);}/*** 获取 key 下的 所有 hashkey 字段** @param key* @return*/public Set<Object> hashKeys(String key) {return redisTemplate.opsForHash().keys(key);}/*** 获取指定 hash 下面的 键值对 数量** @param key* @return*/public Long hashSize(String key) {return redisTemplate.opsForHash().size(key);}//---------------------list类型---------------------/*** 在变量左边添加元素值** @param key* @param value* @return*/public void leftPush(String key, Object value) {redisTemplate.opsForList().leftPush(key, value);}/*** 获取集合指定位置的值。** @param key* @param index* @return*/public Object index(String key, long index) {return redisTemplate.opsForList().index(key, index);}/*** 获取指定区间的值。** @param key* @param start* @param end* @return*/public List<Object> range(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}/*** 把最后一个参数值放到指定集合的第一个出现中间参数的前面,* 如果中间参数值存在的话。** @param key* @param pivot* @param value* @return*/public void leftPush(String key, String pivot, String value) {redisTemplate.opsForList().leftPush(key, pivot, value);}/*** 向左边批量添加参数元素。** @param key* @param values* @return*/public void leftPushAll(String key, String... values) {redisTemplate.opsForList().leftPushAll(key, values);}/*** 向集合最右边添加元素。** @param key* @param value* @return*/public void leftPushAll(String key, String value) {redisTemplate.opsForList().rightPush(key, value);}/*** 向左边批量添加参数元素。** @param key* @param values* @return*/public void rightPushAll(String key, String... values) {redisTemplate.opsForList().rightPushAll(key, values);}/*** 向已存在的集合中添加元素。** @param key* @param value* @return*/public void rightPushIfPresent(String key, Object value) {redisTemplate.opsForList().rightPushIfPresent(key, value);}/*** 向已存在的集合中添加元素。** @param key* @return*/public long listLength(String key) {return redisTemplate.opsForList().size(key);}/*** 移除集合中的左边第一个元素。** @param key* @return*/public void leftPop(String key) {redisTemplate.opsForList().leftPop(key);}/*** 移除集合中左边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。** @param key* @return*/public void leftPop(String key, long timeout, TimeUnit unit) {redisTemplate.opsForList().leftPop(key, timeout, unit);}/*** 移除集合中右边的元素。** @param key* @return*/public void rightPop(String key) {redisTemplate.opsForList().rightPop(key);}/*** 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。** @param key* @return*/public void rightPop(String key, long timeout, TimeUnit unit) {redisTemplate.opsForList().rightPop(key, timeout, unit);}
}
使用:
package com.jerry.springbootredis.demos;import com.jerry.springbootredis.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/redis")
public class BasicController {@Autowiredprivate RedisUtils redisUtils;//    @GetMapping("save")
//    public String save(String key, String value) {
//        redisTemplate.opsForValue().set(key, value);
//        return "ok";
//    }@GetMapping("sMap")public String sMap(String key, String hashKey, String hashVal) {Map<String, String> map = new HashMap<>();map.put(hashKey, hashVal);redisUtils.add(key, map);return "ok";}@GetMapping("getMapString")public String getMapString(String key, String hasKey) {String mapString = redisUtils.getMapString(key, hasKey);return mapString;}@GetMapping("getMapInt")public String getMapInt(String key, String hasKey) {Integer mapInt = redisUtils.getMapInt(key, hasKey);return mapInt.toString();}//.....
}

代码demo地址github🤖


鸣谢:稀土掘金:一缕82年的清风(SpringBoot教程(十四) | SpringBoot集成Redis(全网最全))


总结

以上就是Redis的命令行基本命令介绍,希望对你有所帮助。如果想了解更多关于Redis的内容,可以参考Redis官方文档。

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

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

相关文章

CSS导读 (Emmet语法)

&#xff08;大家好&#xff0c;今天我们将继续来学习CSS的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 续&#xff1a;七、Chrome调试工具 一、Emmet语法 1.1 快速生成HTML结构语法 1.2 快速生成CSS样式语法 &…

LangChain-10 Agents langchainhub 共享的提示词Prompt

LangChainHub 的思路真的很好&#xff0c;通过Hub的方式将Prompt 共享起来&#xff0c;大家可以通过很方便的手段&#xff0c;短短的几行代码就可以使用共享的Prompt。 我个人非常看好这个项目。 官方推荐使用LangChainHub&#xff0c;但是它在GitHub已经一年没有更新了&#x…

如何实现在线程池中执行远程调用可以获取到主线程的请求上下文

public class ThreadPoolConfig {/*** 异步任务执行线程池** return*/Bean("taskExecutor")public TaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor new CustomThreadPoolExecutor();// 设置核心线程数executor.setCorePoolSize(5);// 设置最大线程数…

PyCharm安装教程:详细步骤解析

目录 1. 下载 PyCharm 安装包 2. 运行安装程序 3. 选择安装类型 4. 确认安装选项 5. 安装过程中 6. 安装完成 7. 启动 PyCharm 8. 选择版本 9. 登录或注册 10. 激活许可证 11. 激活成功 PyCharm 是一款功能强大的 Python IDE&#xff08;集成开发环境&#xff09;&a…

flutter多入口点entrypoint

native中引擎对象本身消耗内存(每个引擎对象约莫消耗42MB内存) 多引擎&#xff1a;native多引擎>启动>flutter多入口点entrypoint>多main函数>多子包元素集>多(子)程序 单引擎(复用)&#xff1a;native单引擎>复用启动>flutter多入口点entrypoint>多m…

高等数学基础篇之关于圆,椭圆,圆环的应用

文章目录 前言 1.圆 1.1标准方程 1.2偏心圆 1.3参数方程 2.椭圆 2.1标准方程 2.2参数方程 2.3极坐标 3.圆环 4.扇形 前言 这篇文章主要是应对二重积分出现的一些关于圆的积分域&#xff0c;让大家大概了解一下&#xff0c;不是很详细&#xff0c;因为二重积分对几何…

uniapp请求后端接口

新建文件夹utils const request (config) > {// 拼接完整的接口路径config.url http://mm.test.cn config.url;//这里拼接的是访问后端接口的地址&#xff0c;http://mm.test.cn/prod-api/testconsole.log(config.url)//判断是都携带参数if(!config.data){config.data …

7-26 单词长度

题解&#xff1a; #include <bits/stdc.h> using namespace std; int main() {string s;getline(cin,s); //读取一行字符串char c; //记录字符int cnt 0; //用来记录长度int flag 0; //用来判断是否已经输出了第一个单词的长度for (int i 0;i<s.size(); i)…

【openGL4.x手册14】OpenGL 渲染管道的逻辑运算

目录 一、说明二、逻辑运算三、行动四、写入掩码6.1 颜色掩码6.2 深度mask6.3 模板mask 一、说明 对于渲染管道的混合方案&#xff0c;需要以种种不同混合方案&#xff0c;其中混合的方式用逻辑运算实现。其次&#xff0c;在混合颜色的时候&#xff0c;还有掩码过滤器&#xf…

阿里云新手用户建站必看攻略,从注册域名到网站上线需完成步骤

无论是个人还是企业新手用户&#xff0c;搭建个人或者企业网站都必须进过注册域名、购买云服务器、搭建网站、ICP备案、解析域名等步骤&#xff0c;本文为大家展示阿里云新手用户建站过程中从注册域名到网站上线需要完成的具体步骤。 1、选购域名 域名是互联网世界的门牌号码&…

什么是HW,企业如何进行HW保障?

文章目录 一、什么是HW二、HW行动具体采取了哪些攻防演练措施三、攻击方一般的攻击流程和方法四、企业HW保障方案1.建意识2.摸家底3.固城池4.配神器5.增值守 一、什么是HW 网络安全形势近年出现新变化&#xff0c;网络安全态势变得越来越复杂&#xff0c;黑客攻击入侵、勒索病…

【JavaWeb】Day37.MySQL概述——数据库设计-DML

数据库操作-DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增、删、改操作。 1.增加(insert) insert语法&#xff1a; 向指定字段添加数据 insert into 表名 (字段名1, 字段名2) values (值1, 值2); 全部字段添加数据…

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测 目录 回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测预测效果基本介绍程序设计参考资料预测效果 基本介绍

如何实现小程序滑动删除组件+全选批量删除组件

如何实现小程序滑动删除组件全选批量删除组件 一、简介 如何实现小程序滑动删除组件全选批量删除组件 采用 uni-app 实现&#xff0c;可以适用微信小程序、其他各种小程序以及 APP、Web等多个平台 具体实现步骤如下&#xff1a; 下载开发者工具 HbuilderX进入 【Dcloud 插…

使用Datax自定义采集组件Reader/Writer实现国产数据库支持以及_Datax数据清洗/过滤规则功能自定义---大数据之DataX工作笔记007

我们基于datax来做的自己的数据采集系统,现在基本的数据采集已经实现了,也就是调用datax的数据采集能力,实现在已支持的数据库之间同步数据.我们是基于datax-web实现的,里面都有开源的代码了,可以分析以后拿过来用,这个过程并不复杂,而且,结合xxljob的web那个开源项目,也可以让…

gateway基于redis做限流处理

文章目录 前言一、如何限流&#xff1f;二、使用步骤总结 前言 限流的意义 限流是针对于并发量比较高的时候&#xff0c;如果不针对对应的服务做限流操作&#xff0c;可能造成服务器压力过大&#xff0c;宕机等情况. 一、如何限流&#xff1f; 限流的方式&#xff1a; 计数…

Kafka消费者在Java中的应用

加油&#xff0c;新时代打工人&#xff01; Kafka生产者在Java中的应用 创建Kafka消费者配置 Properties props new Properties(); props.setProperty("bootstrap.servers", "node1.itcast.cn:9092"); props.setProperty("group.id", "t…

Redis 和 Mysql 数据库数据如何保持一致性

Redis 和 Mysql 数据库数据如何保持一致性 保持Redis和MySQL数据库数据一致性是一个常见且重要的问题&#xff0c;特别是在使用Redis作为MySQL数据库的缓存层时。以下是几种常用的保证二者数据一致性的策略和方法&#xff1a; 双写一致性&#xff08;同步更新&#xff09;&…

KIOXIA铠侠CD8P-R NVMe 2.0 PCIe 5.0 KCD81PUG3T84大容量SSD

今天给大家介绍一下KIOXIA铠侠CD8P-R系列3T84容量固态硬盘SSD,这是一款面向数据中心的NVMe™ SSD&#xff0c;专为支持各种规模的分布式和云应用而优化&#xff0c;包括大数据/IoT、在线交易处理和虚拟化。 接口&#xff1a; PCIe 5.0 (32 GT/s x4) 接口 随机读取速度&#x…

Windows完全卸载MySQL后再下载安装(附安装包)

目录 友情提醒第一章&#xff1a;如何完全卸载干净mysql教程&#xff08;三个步骤完全卸载&#xff09;1&#xff09;步骤一&#xff1a;卸载程序2&#xff09;步骤二&#xff1a;删除文件3&#xff09;步骤三&#xff1a;删除注册表信息 第二章&#xff1a;下载软件两种方式1&…