redis持久化与SpringBoot整合

redis持久化与SpringBoot整合

  • 1、Redis全局命令
    • 1.2、Redis事务
  • 2、Redis持久化
    • 2.1、RDB方式
      • 2.1.1、客户端触发机制
      • 2.1.2、服务端触发机制
      • 2.2.3、配置生成快照名称和位置
      • 2.2.4、优点
      • 2.2.5、缺点
    • 2.2、AOF方式
      • 2.2.1、优点
      • 2.2.2、缺点
    • 2.3、RDB-AOF混合方式
    • 2.4、持久化机制的选择
  • 3、SpringBoot整合Redis
    • 3.1、环境准备
    • 3.2、SpringBoot操作key
    • 3.3、SpringBoot操作String
    • 3.4、SpringBoot操作List
    • 3.5、SpringBoot操作Set
    • 3.6、SpringBoot操作ZSet
    • 3.7、SpringBoot操作Hash
    • 3.8、SpringBoot操作对象
    • 3.9、BoundAPI
    • 3.10、总结
    • 5、Redis的应用场景

1、Redis全局命令

全局命令针对的是所有的key,常用的全局key命令如下:

命令格式功能案例
keys pattern按照pattern 匹配规则,列表redis中所有的keykeys xxx:*查询符合 xxx:* 格式的key
exists key判断key是否存在exists name判断 name 字段是否存在
expire key seconds给key设置过期时间,超时:secondsexpire name 10给 name 设置10s
persist key取消key过期时间persist name取消name 的过期时间
select index切换数据库,默认是第0个,共有【0,15】个select 0切换第0个数据库
move key db从当前数据库将key移动到指定db库move name 1将 name 移动到第1个数据库
randomkey随机返回一个keyrandomkey
rename key newkey将key改名为newkeyrename name newname将 name 改名为 newname
echo message打印message信息echo message
dbsize查看key个数dbsize
info查看redis数据库信息info
config get *查看所有redis配置信息config get *
flushdb清空当前数据库flushdb
flushall清空所有数据库flushall

1.2、Redis事务

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set name dafei
QUEUED
127.0.0.1:6379(TX)> set age 18
QUEUED
127.0.0.1:6379(TX)> incr age 
QUEUED
127.0.0.1:6379(TX)> incr name
QUEUED
127.0.0.1:6379(TX)> get age
QUEUED
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) (integer) 19
4) (error) ERR value is not an integer or out of range
5) "19"
6) "dafei"
127.0.0.1:6379> 

​ 单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。Redis事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

​ Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

2、Redis持久化

先来一个小实验:

  1. 在Redis中添加2个key-value对

    127.0.0.1:6379> set aa aa
    OK
    127.0.0.1:6379> set bb bb
    OK
    127.0.0.1:6379> keys *
    # 获取redis中所有的key
    
  2. 重启 redis

    redis-server restart 
    
  3. 再次执行keys *

    keys *
    
  4. 分析结果:会出现如下结果

    • 之前的key在,aa bb 都在(最理想的结果)
    • 之前的key在,aa也在,bb不见了
    • 之前的key在,aa, bb 不在
    • 之前的key, aa, bb 都不在了(最坏的结果)

思考:为啥会这样?以我们对内存的操作理解,按道理重启之后数据应该全丢失了,为啥Redis 可能丢失,也可能不丢失,为何?这里就涉及到Redis的持久化机制了。Redis不定时将内存中的数据存到硬盘中

在这里插入图片描述

Redis持久化机制目前以后3种,分别为:

  1. 快照方式(RDB, Redis DataBase)

  2. 文件追加方式(AOF, Append Only File)

  3. 混合持久化方式(Redis4版本之后)

2.1、RDB方式

Snapshotting(快照)是持久化机制的默认方式,将内存数据中以快照的方式写入到二进制文件(硬盘)中,默认为dump.rdb。触发RDB持久化过程分手动触发与自动触发。

  • 客户端方式: BGSAVE 和 SAVE指令
  • 服务器配置自动触发

2.1.1、客户端触发机制

手动触发

  • 使用save命令:会阻塞当前Redis服务器,知道RDB过程完成为主,如果内存数据较多,会造成长时间阻塞,影响其他命令的使用,不建议轻易使用

  • 使用bgsave命令:Redis进程执行fork指令创建子进程,由子进程实现RDB持久化,有需要时建议使用bgsave命令。

自动触发

使用save相关配置,格式: save m n 表示m秒内数据集存在n次修改时会自动触发bgsave命令。

#900秒内如果超过1个Key被修改则发起快照保存
save 900 1  #300秒内如果超过10个key被修改,则发起快照保存
save 300 10 #10000秒内如果超过60个key被修改,则发起快照保存
save 60 10000

SAVE命令并不常用,使用SAVE命令在快照创建完毕之 前,redis处于阻塞状态,无法对外服务

2.1.2、服务端触发机制

如果用户在redis.conf中设置了save配置选项,redis会在save选项 条件满足之后自动触发一次BGSAVE命令,如果设置多个save配置选项,当任意一个save配置选项条件满足,redis也会触发一次BGSAVE命令

#900秒内如果超过1个Key被修改则发起快照保存
save 900 1  #300秒内如果超过10个key被修改,则发起快照保存
save 300 10 #10000秒内如果超过60个key被修改,则发起快照保存
save 60 10000

2.2.3、配置生成快照名称和位置

# 1.修改生成快照名称
dbfilename dump.rdb# 2.修改生成位置
dir ./   # 这个表示redis-cli、redis-server这些命令的同级目录

2.2.4、优点

  • RDB快照文件是一个紧凑压缩的二进制文件,非常使用用于备份,全量复制等场景。开发中可以按照每6小时执行一次bgsave备份,用于容灾备份。

  • Redis加载RDB恢复数据远远快于AOF方式

2.2.5、缺点

  • RDB无法做到实时持久化/秒级持久化(两次存在硬盘有时间差),每次bgsave时都需要fork子进程,频繁执行有时间成本。
  • RDB快照文件不同版本格式不一样,容易引起兼容问题。

2.2、AOF方式

AOF与RDB不一样,它是以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。解决了数据持久化的实时性的问题。Redis默认是不开启的,需要使用时,需要配置:

# 开启持久化
appendonly yes# 修改生成文件名称
appendfilename "appendonly.aof"# 修改日志同步频率 appendfsync everysec|always|no 指定,推荐everysec
appendfsync everysec

解释一下:就是记录每次的 set、setex等写命令,这样当内存中的数据丢失时,我们将所有的写名字重新执行一遍,这样就恢复了内存的数据。

AOF 有3种文件同步策略:

策略解释
appendfsync always收到命令就立即写到磁盘,效率最慢.但是能保证完全的持久化
appendfsync everysec每秒写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
appendfsync no完全以依赖os,一般同步周期是30秒

2.2.1、优点

  • AOF方式数据安全性更高,配置得当,最多损失1秒的数据量

  • 在不小心执行flushall命令,也可以通过AOF方式恢复(删除最后一个命令即可)

  • AOF 日志是一个增量日志文件,不会存在断电时出现损坏问题。即使出现问题,redis-check-aof 工具也能够轻松修复它。

  • 当 AOF 变得太大时,Redis 能够在后台自动重写 AOF

2.2.2、缺点

  • 相同数据量来说,AOF文件体积通常大于RDB文件
  • 数据持久化性能上来说,AOF 比 RDB 慢

2.3、RDB-AOF混合方式

混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件。即以 RDB 作为全量备份,AOF 作为增量备份,来提高备份效率。这样既能保证 Redis 重启时的速度,又能防止数据丢失的风险, 这就是 Redis 4.0 之后推出的 RDB-AOF 混合持久化模式,其作为默认配置来使用

2.4、持久化机制的选择

  • 如果对数据安全性有非常高的要求,建议 RDB 和 AOF 同时启用。
  • 如果对数据安全性要求不是很高,能够容忍数据的丢失,建议单独使用 RDB。
  • 不推荐单独使用 AOF,因为对于进行数据库备份、更快重启以及 AOF 引擎中出现错误的情况来说,RDB 是更好的选择。
  • 如果没特殊要求,Redis又是4.x版本以上,可以选择RDB-AOF混合方式。

3、SpringBoot整合Redis

Spring Boot Data(数据)Redis中提供了RedisTemplateStringRedisTemplate,其中StringRedisTemplateRedisTemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同

  • RedisTemplate中的两个泛型都是Object,意味着存储的key和value都可以是一个对象
  • StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。

注意: 使用RedisTemplate默认是将对象序列化到Redis中,所以放入的对象必须实现对象序列化接口 serilizable

3.1、环境准备

  1. 引入依赖
<!--redis依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis连接池-->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
  1. 配置application.yaml
spring:redis:host: 192.168.126.132port: 6379password: 1234lettuce:pool:max-active: 8 # 最大连接max-idle: 8   # 最大空闲连接min-idle: 0   # 最小空闲连接max-wait: 100ms # 连接等待时间
  1. 写完上述配置,我们启动 SpringBoot 时,会给我们自动创建 RedisTemplateStringRedisTemplate,我们只需要注入即可
@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 测试存字符串String@Testvoid testSaveString() {// 写入一条String数据stringRedisTemplate.opsForValue().set("name","虎哥");// 获取String数据Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name = " + name);}}

3.2、SpringBoot操作key

  • stringRedisTemplate.delete("key") : 删除一个key
  • stringRedisTemplate.hasKey("key") : 是否有 name 这个key
  • stringRedisTemplate.type("key") : 查看 key 的类型
  • stringRedisTemplate.keys("*") : 查看所有的 key
@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 测试操作redis中的key@Testvoid testKey(){// 删除一个key// stringRedisTemplate.delete("name");// 判断某个key是否存在Boolean hasKey = stringRedisTemplate.hasKey("name");System.out.println(hasKey);// 判断key所对应value的类型DataType type = stringRedisTemplate.type("name");System.out.println(type);// 获取所有的keySet<String> keys = stringRedisTemplate.keys("*");keys.forEach(key -> System.out.println("key = " + key));// 测试key的超时时间 -1表示永不超时, -2 表示 key 不存在Long expire = stringRedisTemplate.getExpire("name");System.out.println(expire);// 随机获取一个keyString s = stringRedisTemplate.randomKey();System.out.println(s);//修改key的名字(判断key是否存在,存在才会修改)stringRedisTemplate.renameIfAbsent("name","name1");// 移动key到指定库stringRedisTemplate.move("name",1);}}

3.3、SpringBoot操作String

@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;// 测试操作字符串String@Testvoid testSaveString() {// 写入一条String数据stringRedisTemplate.opsForValue().set("name","虎哥");// 获取String数据Object name = stringRedisTemplate.opsForValue().get("name");System.out.println("name = " + name);// 设置key的超时时间(设置一个code的key,值value是2357,超时时间是120,单位是TimeUnit.SECONDS 为秒)stringRedisTemplate.opsForValue().set("code","2357",120, TimeUnit.SECONDS);// 给key对应的value追加值stringRedisTemplate.opsForValue().append("name","他是一个好人,单纯少年!");}}

3.4、SpringBoot操作List

  • stringRedisTemplate.leftPush("key","xxx") : 创建一个列表 并放入一个元素
  • stringRedisTemplate.leftPushAll("key","xxx,xxx,xxx") : 创建一个列表 并放入多个元素
  • stringRedisTemplate.opsForList().range("names", 0, -1) : 获取列表,返回一个List集合
  • stringRedisTemplate.opsForList().index("List", "index") : 获取列表中指定下标所对应的值
  • stringRedisTemplate.opsForList().leftPop("List") : 从列表左边弹出一个元素
@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;//操作redis中list类型   opsForList 实际操作就是redis中list类型@Testpublic void testList(){//stringRedisTemplate.opsForList().leftPush("names","小陈");//创建一个列表  并放入一个元素//stringRedisTemplate.opsForList().leftPushAll("names","小陈","小张","小王");//创建一个列表 放入多个元素List<String> names = new ArrayList<>();names.add("xiaoming");names.add("xiaosan");//stringRedisTemplate.opsForList().leftPushAll("names",names);//创建一个列表 放入多个元素// 查看列表List<String> stringList = stringRedisTemplate.opsForList().range("names", 0, -1); stringList.forEach(value-> System.out.println("value = " + value));}}

3.5、SpringBoot操作Set

@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;//操作redis中set类型   opsForSet 实际操作就是redis中set类型@Testpublic void testSet(){//创建set 并放入多个元素stringRedisTemplate.opsForSet().add("sets","张三","张三","小陈","xiaoming");//查看set中成员Set<String> sets = stringRedisTemplate.opsForSet().members("sets");sets.forEach(value-> System.out.println("value = " + value));//获取set集合元素个数Long size = stringRedisTemplate.opsForSet().size("sets");System.out.println("size = " + size);}}

3.6、SpringBoot操作ZSet

@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testpublic void testZset(){//创建ZSet并放入元素(小黑的分数是20)stringRedisTemplate.opsForZSet().add("zsets","小黑",20);//指定范围查询Set<String> zsets = stringRedisTemplate.opsForZSet().range("zsets", 0, -1);zsets.forEach(value-> System.out.println(value));System.out.println("=====================================");//获取指定元素以及分数(分数在0-1000之间)Set<ZSetOperations.TypedTuple<String>> zsets1 = stringRedisTemplate.opsForZSet().rangeByScoreWithScores("zsets", 0, 1000);zsets1.forEach(typedTuple ->{System.out.println(typedTuple.getValue());System.out.println(typedTuple.getScore());});}}

3.7、SpringBoot操作Hash

@SpringBootTest
class KuangStudyRedisApplicationTests {//注入StringRedisTemplate@Autowiredprivate StringRedisTemplate stringRedisTemplate;//操作redis中Hash类型   opsForHash 实际操作就是redis中Hash类型@Testpublic void testHash(){//创建一个hash类型 并放入key valuestringRedisTemplate.opsForHash().put("maps","name","张三");Map<String,String> map =  new HashMap<String,String>();map.put("age","12");map.put("bir","2012-12-12");//放入多个key valuestringRedisTemplate.opsForHash().putAll("maps",map);//获取多个key的valueList<Object> values = stringRedisTemplate.opsForHash().multiGet("maps", Arrays.asList("name", "age"));values.forEach(value-> System.out.println(value));//获取hash中某个key的值String value  = (String) stringRedisTemplate.opsForHash().get("maps", "name");//获取所有valuesList<Object> vals = stringRedisTemplate.opsForHash().values("maps");//获取所有keysSet<Object> keys = stringRedisTemplate.opsForHash().keys("maps");}}

3.8、SpringBoot操作对象

SpringBoot操作对象是采用RedisTemplate,RedisTemplate默认是将对象序列化到 Redis 中,所以放入的对象必须实现对象序列化接口。

在存对象时,我们会让key采用StringRedisSerializer方式,而value采用默认的JdkSerializationRedisSerializer序列化方式。

  • redisTemplate.setKeySerializer(new StringRedisSerializer()) : 修改key的序列化,使得存key的序列化采用StringRedisSerializer方式
  • redisTemplate.setHashKeySerializer(new StringRedisSerializer()) : 在我们操作Hash类型时,也要加上这一句,使得修改hash key 的序列化(因为Hash有两个key
@SpringBootTest
public class KuangStudyRedisTemplateTests {// 注入RedisTemplate@Autowiredprivate RedisTemplate redisTemplate;void testRedisTemplate(){// 修改key的序列化,使得存key的序列化采用StringRedisSerializer方式redisTemplate.setKeySerializer(new StringRedisSerializer());// 修改hash key 的序列化redisTemplate.setHashKeySerializer(new StringRedisSerializer());// 创建一个User对象User user = new User();user.setId(UUID.randomUUID().toString());user.setName("林晓");user.setAge(23);user.setBir(new Date());// 将对象序列化后存入redisredisTemplate.opsForValue().set("user",user);// 获取对象需要进行反序列化User user1 = (User) redisTemplate.opsForValue().get("user");System.out.println(user1);// 创建一个列表并放入user对象redisTemplate.opsForList().leftPush("list",user);// 创建一个Set并放入user对象redisTemplate.opsForSet().add("set",user);// 创建一个ZSet并放入user对象redisTemplate.opsForZSet().add("zset",user,10);// 创建一个Hash并放入user对象(注意需要序列化两个key)redisTemplate.opsForHash().put("map","name",user);}
}

3.9、BoundAPI

BoundAPI可以绑定某个key,后续的所有操作都是针对这个key进行操作的。

@SpringBootTest
public class KuangStudyBoundAPITests {@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate StringRedisTemplate stringRedisTemplate;// spring data 为了方便我们对redis进行更友好的操作 因此有提供了bound api 简化操作@Testpublic void testBound(){// 对key序列化redisTemplate.setKeySerializer(new StringRedisSerializer());// 对Hash key 序列化redisTemplate.setHashKeySerializer(new StringRedisSerializer());//对字符串类型key进行绑定 后续所有操作都是基于这个key的操作BoundValueOperations<String, String> nameValueOperations = stringRedisTemplate.boundValueOps("name");// 对name设置value为张三nameValueOperations.set("张三");// 对name的value追加nameValueOperations.append("是一个好人");// 获取name的valueString s1 = nameValueOperations.get();System.out.println(s1);//对list set zset hash//对list类型key进行绑定 后续所有操作都是基于这个key的操作BoundListOperations<String, String> listsOperations = stringRedisTemplate.boundListOps("lists");// 对lists设置valuelistsOperations.leftPushAll("张三","李四","小陈");// 获取listsList<String> lists = listsOperations.range(0, -1);lists.forEach(list-> System.out.println(list));//set//redisTemplate.boundSetOps();//stringRedisTemplate.boundSetOps()//zset//stringRedisTemplate.boundZSetOps();//redisTemplate.boundZSetOps();//hash//stringRedisTemplate.boundHashOps();//redisTemplate.boundHashOps()}

3.10、总结

  1. 针对于日后处理key value 都是 String 使用 StringRedisTemplate
  2. 针对于日后处理的key value 存在对象 使用 RedisTemplate
  3. 针对于同一个key多次操作可以使用boundXXXOps()
    • XXX包含: Value List Set Zset Hash的 api 简化书写

5、Redis的应用场景

  1. 利用redis 中字符串类型完成项目中手机验证码存储的实现
  2. 利用redis 中字符串类型完成具有失效性业务功能。 例如12306,淘宝的订单还有:40分钟
  3. 利用redis 分布式集群系统中: Session共享
  4. 利用redis zset类型:可排序set类型,元素,分数,排行榜之类功能
  5. 利用redis 实现分布式缓存
  6. 利用redis 存储认证之后token信息
  7. 利用redis 解决分布式集群系统中分布式锁问题

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

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

相关文章

Nginx配置jks格式证书,升级https

通常在给服务器升级https&#xff0c;需要在nginx上配置域名对应的https证书&#xff0c;nginx通常配置的是crt和key格式的证书。最近遇到有人提供了jks格式的证书&#xff0c;查阅了几个资料都是需要先将jks转为p12格式&#xff0c;然后再将p12转为crt格式。这里记录一下相关过…

在JavaFX中的module-info.java的大坑,实现怎么删除这个后不会报错“需要JavaFX运行组件”

如果你也是因为module-info导致项目一些依赖包不能用&#xff0c;那么可以试着删除这个模块&#xff1b;话不多说&#xff0c;请看image 1.首先删除你的module-info.java&#xff08;注意&#xff1a;你要是怕出错的话&#xff0c;建议提前备份你的项目&#xff09; 2.然后找到…

影视视频知识付费行业万能通用网站系统源码,三网合一,附带完整的安装部署教程

在数字化时代&#xff0c;知识付费行业逐渐成为主流。人们对高质量内容的需求日益增长&#xff0c;越来越多的人愿意为有价值的知识和信息服务付费。为了满足这一市场需求&#xff0c;罗峰给大家分享一款全新的影视视频知识付费网站系统源码&#xff0c;为用户提供一站式的知识…

electron自定义窗口和右键菜单样式

前言 electron默认沿用系统UI&#xff0c;并没有提供很多接口供使用者定制样式&#xff0c;如果想要完全自定义的样式&#xff0c;目前我能想到的方案只能是通过前端自定义样式&#xff0c;然后通过进程通信来实现系统基础功能&#xff1a;最大/小化、关闭、拖动窗口等。 效果…

面试宝典进阶之关系型数据库面试题

D1、【初级】你都使用过哪些数据库&#xff1f; &#xff08;1&#xff09;MySQL&#xff1a;开源数据库&#xff0c;被Oracle公司收购 &#xff08;2&#xff09;Oracle&#xff1a;Oracle公司 &#xff08;3&#xff09;SQL Server&#xff1a;微软公司 &#xff08;4&#…

麒麟系统安装docker、mysql、clickhouse

1、查看麒麟系统版本信息 cat /etc/os-release 麒麟系统版本V10 64位操作系统 # uname -p x86_64 # uname -p aarch64 内核版本 # uname -r 4.19.90-24.4.v2101.ky10.x86_64 本操作为麒麟系统版本V10&#xff0c;x86_64操作系统 一&#xff0c;安装docker 文件&#xff1a…

MySQL数据库备份脚本(mysqldump)

数据库备份脚本 以下shell脚本的主要目的是备份数据库&#xff0c;并在需要时删除旧的备份文件以节省空间。它使用 mysqldump 命令来执行数据库备份&#xff0c;将备份文件存储在指定的路径下&#xff0c;并根据文件数量的阈值来删除旧的备份文件。扫描文章末尾二维码关注公众…

debug OpenBLAS library 和 应用示例

1. 构建openblas lib git clone gitgithub.com:OpenMathLib/OpenBLAS.git cd OpenBLAS/ 如果要安装在自定义文件夹中&#xff0c;可以修改 PREFIX 的定义&#xff1a; 将 PREFIX /opt/OpenBLAS 修改成 PREFIX ../local/ 然后构建&#xff1a; make -j make install 如果要…

基于filter的内存马

主要是通过过滤器来拦截severlet请求中的参数&#xff0c;作为过滤器中的参数&#xff0c;来调用自定义过滤器中的恶意函数 在这里我们分析一下filter的实现原理&#xff0c;循序渐进 Demo1&#xff1a; 直接使用filter模拟内存马效果&#xff1a; 1.配置一个简单的severlet的…

推荐VSCODE插件:为`package.json`添加注释信息

众所周知&#xff0c;JSON文件是不支持注释的&#xff0c;除了JSON5/JSONC之外&#xff0c;我们在开发项目特别是前端项目时&#xff0c;大量会用到JSON文件&#xff0c;特别是在编写package.json中的scripts时&#xff0c;由于缺少注释,当有大量的命令脚本时&#xff0c;就有了…

给自己创建的GPTs添加Action(查天气)

前言 在这篇文章中&#xff0c;我将分享如何利用ChatGPT 4.0辅助论文写作的技巧&#xff0c;并根据网上的资料和最新的研究补充更多好用的咒语技巧。 GPT4的官方售价是每月20美元&#xff0c;很多人并不是天天用GPT&#xff0c;只是偶尔用一下。 如果调用官方的GPT4接口&…

Qt中QGraphicsView总体架构学习

前沿 前段时间学习了下如何在QGraphicsView架构中绘制刻度尺&#xff0c;主要是与OnPainter中进行比较的&#xff0c;那么今天就来详细讲解下我对QGraphicsView框架的认知吧~ 最近一段时间想学习下&#xff0c;如果我有不正确的&#xff0c;欢迎留言探讨哟~ QGraphicsView架…

[软件工具]AI软件离线表格识别工具使用教程图像转excel转表格可复制文字表格导出实时截图识别成表格

【官方框架地址】 https://github.com/PaddlePaddle/PaddleOCR.git 【算法介绍】 PaddleOCR是一个基于PaddlePaddle框架的开源光学字符识别&#xff08;OCR&#xff09;工具库&#xff0c;由百度公司开发。它提供了一套完整的OCR解决方案&#xff0c;包括文字检测、文字识别以…

使用 Apache PDFBox 操作PDF文件

简介 Apache PDFBox库是一个开源的Java工具&#xff0c;专门用于处理PDF文档。它允许用户创建全新的PDF文件&#xff0c;编辑现有的PDF文档&#xff0c;以及从PDF文件中提取内容。此外&#xff0c;Apache PDFBox还提供了一些命令行实用工具。 Apache PDFBox提供了创建、渲染、…

linux环境安装docker

一、Docker是什么? 当我们开发一个应用程序时&#xff0c;通常需要配置和安装各种软件、库和依赖项。而这些环境配置可能会因为不同的操作系统或版本而存在差异&#xff0c;导致应用在不同环境中运行出现问题。 Docker就像是一个集装箱&#xff0c;可以将应用程序及其所有依…

Java EE 博客系统(Servlet版)

文章目录 1. 基本情况2. 准备工作3. 博客列表页4. 博客详情页5. 实现登录6. 强制要求登录7. 显示用户信息8. 退出登录9. 发布博客10. 如果程序出现问题怎么办&#xff1f; 1. 基本情况 这里的博客系统主要是四个界面 博客列表页 显示出当前网站上都有哪些博客博客详情页 点击…

浅析ARMv8体系结构:A64指令集

文章目录 A64指令编码格式加载与存储指令寻址模式变基模式前变基模式后变基模式 PC相对地址模式 伪指令加载与存储指令的变种不同位宽的加载与存储指令多字节内存加载和存储指令基地址偏移量模式前变基模式后变基模式 跳转指令返回指令比较并跳转指令 其它指令内存独占访问指令…

面试题:MySQL误删表数据,如何快速恢复丢失的数据?

相信后端研发的同学在开发过程经常会遇到产品临时修改线上数据的需求&#xff0c;如果手法很稳那么很庆幸可以很快完成任务&#xff0c;很不幸某一天突然手一抖把表里的数据修改错误或者误删了&#xff0c;这个时候你会发现各种问题反馈接踵而来。 如果身边有BDA或者有这方面经…

Kubernetes WebHook 入门 -- 入门案例: apiserver 接入 github

博客原文 文章目录 k8s 集群配置介绍Admission WebhookWebHook 入门实践: github 认证接入web 服务器Dockerfile 镜像制作amd64x86_64构造镜像检验镜像 Makefilewebhook 接入 apiserverwebhook.yamlapiserver 挂载 webconfig在 github 中创建认证 token将 token 添加到 kubecon…

AI绘画:Midjournety的使用体验

今天的时间少&#xff0c;没有给大家做一些教程&#xff0c;就单纯分享使用体验&#xff0c;还不错&#xff0c;体验感很好。 后需如果有需要&#xff0c;我可以出一些教程类的视频。 下面是一组复刻fated的saber的一组提示词&#xff0c;效果相当不错。我后续会分享一些学习经…