【Redis学习2】Redis常用数据结构与应用场景
Redis常用数据结构与应用场景
redis中存储数据是以key-value
键值对的方式去存储的,其中key为string字符类型,value的数据类型可以是string(字符串)、list(列表)、hash(字典)、set(集合) 、 zset(有序集合)。 这5种数据类型在开发中可以应对大部分场景的存储
拓展:key的底层存储方式SDS
这里有一个问题,当我们使用一条redis命令set key value
的时候,redis进行了什么操作?
其实当我们使用命令操作redis的时候,也是会经过redis客户端到redis服务端的过程,这些命令相当于一个请求
- redis客户端通过socket传输这些命令
- redis服务端通过io读取到这些请求命令,把所有的命令解析成一个字符串,并执行对应命令操作,然后再经过socket写回操作结果!
同时redis是使用c语言写的,但它底层在存放redis的key时,并没有用c语言原生的字符串数据结构,而是定义了一个属于redis的数据结构SDS(Simple Dynamic String),
struct sdshdr{//记录buf数组中已使用字节的数量//等于 SDS 保存字符串的长度int len;//记录 buf 数组中未使用字节的数量int free;//字节数组,用于保存字符串char buf[];
}
为什么要用这样的一个数据结构去存储字符串呢?
- 二进制安全的数据结构。 比如是操作命令是
get aaa\0
:获取aaa\0
的值。如果是c语言的字符数组就会把\0
吞掉,变为get aaa
,而使用SDS
就会完整的操作aaa\0
,SDS
把所有接受到的数据都转成字符串,即使是一些特殊字符! - SDS提供了内存预分配机制,避免频繁的内存分配。 如果是c语言,在修改一个key时,会分配一个新的字符数组,然后进行内存赋值,而SDS则采用预先分配机制,直接把字符串容量扩大两倍,key的长度变化时,直接在已分配的内存中修改即可,如果不够继续扩大2倍
思考:SDS采用的也是一种空间换时间的思路,无论是扩展之后分配多余空间从而降低下次扩展时需要再次内存分配的概率,还是缩容之后并不立即回收空间而是留给下次扩容,这两种操作都会导致空闲空间增大,内存占用提升,而Redis又了很多数据压缩策略来控制内存。 - 杜绝缓冲区溢出。 在C语言原生的字符串中,当需要修改字符串且修改后的长度大于修改前的长度时,在修改之前需要先对原数组申请空间扩容,否则可能导致数组溢出,内容写入到相邻的下一个数组中从而改变下一个字符串的值。
在SDS中,SDS屏蔽了用户对数组空间的分配,SDS在增长之前会根据free属性自动检测是否足够修改之后的字符串所需空间,如果足够则直接修改,并更新修改之后的len和free属性,如果当前剩余空间不够,SDS会根据空间分配策略自动进行扩容,无需用户关心。
思考:类似于Java中的String类,高级容器等,会提供自动扩容,缩容的功能,具体的细节对使用者透明,能减少开发者的编码负担。
string+应用场景
常用操作
命令 | 说明 |
---|---|
SET key value | 存入字符串键值对 |
MSET key value [key value …] | 批量存储字符串键值对 |
SETNX key value | 存入一个不存在的字符串键值对 |
GET key | 获取一个字符串键值 |
MGET key [key …] | 批量获取字符串键值 |
EXPIRE key seconds | 设置一个键的过期时间(秒) |
DEL key [key …] | 删除一个键 |
INCR key | 将key中储存的数字值加1 |
DECR key | 将key中储存的数字值减1 |
INCRBY key increment | 将key所储存的值加上increment |
DECRBY key decrement | 将key所储存的值减去decrement |
- 设置和获取键值对
> SET key value
OK
> GET key
"value"
值得注意的是, 当key存在时,set命令会覆盖掉你上一次设置的值
> SET key newValue
OK
> GET key
"newValue"
- 使用
EXISTS
和DEL
关键字来查询是否存在和删除键值对:
> EXISTS key
(integer) 1
> DEL key
(integer) 1
> GET key
(nil)
- 批量设置键值对
> SET key1 value1
OK
> SET key2 value2
OK
> MGET key1 key2 key3 # 返回一个列表
1) "value1"
2) "value2"
3) (nil)
> MSET key1 value1 key2 value2
> MGET key1 key2
1) "value1"
2) "value2"
- 过期和 SET 命令扩展
可以对 key 设置过期时间,到时间会被自动删除,这个功能常用来控制缓存的失效时间。(过期可以是任意数据结构)
> SET key value1
> GET key
"value1"
> EXPIRE name 5 # 5s 后过期
... # 等待 5s
> GET key
(nil)
- 返回原值的 GETSET 命令
对字符串,还有一个 GETSET 比较让人觉得有意思,它的功能跟它名字一样:为 key 设置一个值并返回原值:
> SET key value
> GETSET key value1
"value"
这可以对于某一些需要隔一段时间就统计的 key 很方便的设置和查看,例如:系统每当由用户进入的时候你就是用 INCR
命令操作一个 key,当需要统计时候你就把这个 key 使用 GETSET
命令重新赋值为 0,这样就达到了统计的目的。
使用场景
- 单值缓存
SET key value
GET key
使用这两条命令可以做用户id存储、商品库存存储等等!
- 对象存储
以缓存user对象为例,有以下两种方式:
(1)SET user:1 value(json格式数据):把对象转json存入redis,也是当下常用的方式,获取数据需要做数据转换
(2)MSET user:1:name zhuge user:1:balance 1888
MGET user:1:name user:1:balance
使用Mset命令,把对象拆开存储,每一个key只保存对象的一个字段信息,适用于经常修改user的某个字段的场景 - 分布式锁
SETNX product:10001 true //操作product:10001
##执行业务操作...
DEL product:10001 //删除product:10001
其中SETNX key value 命令要求如果key已存在,则其他的setnx命令无法对当前key进行操作。
在使用分布式锁时通常还会通过
SET product:10001 true ex 10 nx 命令设置key的超时时间,防止死锁!
- 计数器
NCR 文章id
可以使用INCR命令实现数量自增,可以用于文章阅读量、热度人数统计等,用户每点进去一次执行一次INCR命令
- 分布式系统全局序列号
在分布式系统下,如果需要分库分表, mysql的数据库自增id已经无法满足分库分表下的id自增,这时就需要一个独立于数据库之外的中间件来实现id的分配。
redis的INCR命令可以实现id、序列号的生成,但如果用户量非常大,每生成一个id、序列号都去redis会给redis添加不小的压力,我们可以一次性从redis中自增1000次,把序列号放入本地内存中,这1000个id用完了,再去redis再取1000个,可有效降低redis的压力!
hash+应用场景
Redis 中的字典(hash)相当于 Java 中的 HashMap,内部实现也差不多类似,都是通过 “数组 + 链表” 的链地址法来解决部分 哈希冲突,同时这样的结构也吸收了两种不同数据结构的优点。
常用操作
命令 | 说明 |
---|---|
HSET key field value | 存储一个哈希表key的键值 |
HGET key field | 获取哈希表key对应的field键值 |
HMSET key field value [field value …] | 在一个哈希表key中存储多个键值对 |
HMGET key field [field …] | 批量获取哈希表key中多个field键值 |
HSETNX key field value | 存储一个不存在的哈希表key的键值 |
HDEL key field [field …] | 删除哈希表key中的field键值 |
HLEN key | 返回哈希表key中field的数量 |
HGETALL key | 返回哈希表key中所有的键值 |
HINCRBY key field increment | 为哈希表key中field键的值加上增量increment |
字典相关操作
> HSET books java "think in java" # 命令行的字符串如果包含空格则需要使用引号包裹
(integer) 1
> HSET books python "python cookbook"
(integer) 1
> HGETALL books # key 和 value 间隔出现
1) "java"
2) "think in java"
3) "python"
4) "python cookbook"
> HGET books java
"think in java"
> HSET books java "head first java"
(integer) 0 # 因为是更新操作,所以返回 0
> HMSET books java "effetive java" python "learning python" # 批量操作
OK
使用场景
- 电商购物车
1)以用户id为key === cart:1001
2)以商品id为field===10088
3)商品数量为value === 1
因此,购物车操作可以如下:
1)添加商品:hset cart:1001 10088 1
2)增加数量hincrby cart:1001 10088 1
3)商品总数hlen cart:1001
4)删除商品hdel cart:1001 10088
5)获取购物车所有商品hgetall cart:1001
思考-优点:
1)同类数据归类整合储存,方便数据管理
2)相比string操作消耗内存与cpu更小
因为:string类型通过set key - val 的方式存储数据,通过对key进行hash运算决定当前key是存储在数组哪个位置。如果把hash类型的数据变成string类型来存储,则需要更多的key,同时在存放时也需要更多的hash(key)运算,消耗更多的cpu资源!
3)相比string储存更节省空间
如果把hash类型的数据变成string类型来存储,将需要存储更多key,如果数据量很多的情况下,redis底层那么存储数据的数组将很快会被占满,占满就会进行扩容,加大内存消耗。由此可见,string结构与hash结构只存储一个key相比,需要更多的内存空间!
思考-缺点:
1)过期功能不能使用在field上,只能用在key上
redis的过期时间只能用在key上,而hash的key是一个大的概念,里面的map型结构才是重要数据,但过期时间只能用在外边的大key上,hash结构相比于string不能实现精准过期!
2)hash结构在Redis集群架构下不适合大规模使用
因为如果一个hash的key中的属性很多的话,只能存在一个redis节点上,那么这个节点压力会比其他节点压力大很多,造成redis集群下压力分配不均衡!
list+应用场景
Redis 的列表相当于 Java 语言中的 LinkedList,注意它是链表而不是数组。这意味着 list 的插入和删除操作非常快,时间复杂度为 O(1),但是索引定位很慢,时间复杂度为 O(n)。
常用操作
命令 | 说明 |
---|---|
LPUSH key value [value …] | 将一个或多个值value插入到key列表的表头(最左边) |
RPUSH key value [value …] | 将一个或多个值value插入到key列表的表尾(最右边) |
LPOP key | 移除并返回key列表的头元素 |
RPOP key | 移除并返回key列表的尾元素 |
LRANGE key start stop | 返回列表key中指定区间内的元素,区间以偏移量start和stop指定 |
BLPOP key [key …] timeout | 从key列表表头弹出一个元素,若列表中没有元素,阻塞等待 |
timeout:秒,如果timeout=0,一直阻塞等待 | |
BRPOP key [key …] timeout | 从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待 |
timeout:秒,如果timeout=0,一直阻塞等待 |
list相关
LPUSH
和RPUSH
分别可以向list的左边(头部)和右边(尾部)添加一个新元素LRANGE
命令可以从list中取出一定范围的元素LINDEX
命令可以从list中取出指定下标的元素,相当于java量表操作中的get(int index)
操作
> rpush mylist A
(integer) 1
> rpush mylist B
(integer) 2
> lpush mylist first
(integer) 3
> lrange mylist 0 -1 # -1 表示倒数第一个元素, 这里表示从第一个元素到最后一个元素,即所有
1) "first"
2) "A"
3) "B"
- list 实现队列
队列是先进先出的数据结构,常用于消息排队和异步逻辑处理,它会确保元素的访问顺序:
> RPUSH books python java golang
(integer) 3
> LPOP books
"python"
> LPOP books
"java"
> LPOP books
"golang"
> LPOP books
(nil)
- list 实现栈
栈是先进后出的数据结构,跟队列正好相反
> RPUSH books python java golang
> RPOP books
"golang"
> RPOP books
"java"
> RPOP books
"python"
> RPOP books
(nil)
list的使用场景
- 模拟分布式系统数据结构
①:Stack(栈) = LPUSH(左边放) + LPOP(左边取)
②:Queue(队列)= LPUSH(左边放) + RPOP(右边取)
③:Blocking MQ(阻塞队列)= LPUSH(左边放) + BRPOP(右边阻塞取:没有数据就阻塞!)
思考:那么redis实现的数据结构和jdk中提供的数据结构有什么区别呢?
答:jdk提供的数据结构仅在本服务中有用,如果在分布式环境下,则需要借助redis等中间件,模拟数据结构来统一管理数据。 - 微博、朋友圈、公众号等,关注的文章列表展示
假如 小明 关注了 中国青年报、三太子敖丙 等大V的订阅号,当这些大V发布订阅号时,通过推或拉的方式把消息LPUSH放入redis中属于小明的list中。其中key为msg:{小明_ID}。当小明要获取大V们发的消息时,使用LRANGE 命令从队列中获取指定个数的订阅号信息!!
# ①:MacTalk发微博,消息ID为10010
LPUSH msg:{小明_ID} 10010# ②:备胎说车发微博,消息ID为10086
LPUSH msg:{小明_ID} 10086# ③:查看最新微博消息(前4条)
LRANGE msg:{小明_ID} 0 4
思考:大V发了消息的是怎么存储在粉丝的redis中呢?一般有两种处理方案!
(1)推送,博主发了消息,通过线程先推送到在线粉丝的队列中,其他不在线的粉丝等后面系统在空闲的时候再慢慢推送过去
(2)拉取,如果粉丝太多,推的方案还是要很长时间去处理,还有一种方案就是拉,每一个粉丝上线后就去关注的博主那里拉取他发送的最新的消息,在使用LRANGE
取出即可。
set+应用场景
Redis 的集合相当于 Java 语言中的 HashSet,它内部的键值对是无序、唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL。
set 的常用操作
命令 | 说明 |
---|---|
SADD key member [member …] | 往集合key中存入元素,元素存在则忽略,若key不存在则新建 |
SREM key member [member …] | 从集合key中删除元素 |
SMEMBERS key | 获取集合key中所有元素 |
SCARD key | 获取集合key的元素个数 |
SISMEMBER key member | 判断member元素是否存在于集合key中 |
SRANDMEMBER key [count] | 从集合key中选出count个元素,元素不从key中删除 |
SPOP key [count] | 从集合key中选出count个元素,元素从key中删除 |
set 的运算操作
命令 | 说明 |
---|---|
SINTER key [key …] | 交集运算 |
SINTERSTORE destination key [key …] | 将交集结果存入新集合destination中 |
SUNION key [key …] | 并集运算 |
SUNIONSTORE destination key [key …] | 将并集结果存入新集合destination中 |
SDIFF key [key …] | 差集运算 |
SDIFFSTORE destination key [key …] | SDIFFSTORE destination key [key …] |
集合set的基本使用
> SADD books java
(integer) 1
> SADD books java # 重复
(integer) 0
> SADD books python golang
(integer) 2
> SMEMBERS books # 注意顺序,set 是无序的
1) "java"
2) "python"
3) "golang"
> SISMEMBER books java # 查询某个 value 是否存在,相当于 contains
(integer) 1
> SCARD books # 获取长度
(integer) 3
> SPOP books # 弹出一个
"java"
set的使用场景
- 抽奖活动
1)点击参与抽奖加入集合
SADD key {userlD}
2)查看参与抽奖所有用户
SMEMBERS key
3)随机抽取count名中奖者
SRANDMEMBER key [count] ------元素不从集合中删除
SPOP key [count] ------ 元素从集合中删除 - 朋友圈点赞
当某人在朋友圈发布消息,可用set来点赞展示
1)点赞
SADD like:{消息ID} {用户ID}
2)取消点赞
SREM like:{消息ID} {用户ID}
3)检查用户是否点过赞
SISMEMBER like:{消息ID} {用户ID}
4)获取点赞的用户列表
SMEMBERS like:{消息ID}
5)获取点赞用户数
SCARD like:{消息ID} - 利用set的交、并、差集实现微博、微信关注模型
关注模型如下图:
首先了解一下set的集合操作,假如有三个集合
set1:(a、b、c)
set2:(b、c、d)
set3:(c、d、e)
三个集合的
交集为:SINTER set1 set2 set3 ==> { c }
并集为:SUNION set1 set2 set3 ==> { a,b,c,d,e }
差集为:SDIFF set1 set2 set3 ==> { a }
差集计算方式:set1 - (set2并set3) = {a、b、c} - {b、c、d、e} = {a} 只保留a中单独存在的元素
共同关注A的人:可以用交集来实现
我可能认识的人:可以使用差集来实现,把我的好友求差集,例如a的好友={b,c},b的好友={a,c,d},那么a可能认识的人可以是,b-a={a,b,c,d}-{a,b,c} = {d}。当然这只是一个简单又不大现实的想法,相当于把对方的好友全部推荐给你了,真实情况的还需要考虑到关系网络,好友的权重数等
zset+应用场景
这可能使 Redis 最具特色的一个数据结构了,它类似于 Java 中 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以为每个 value 赋予一个 score 值,用来代表排序的权重。
zset相比于set多一个score 分值,正是根据这个分值进行排序,所以zset才能展示有序的数据
zset 的常用操作
命令 | 说明 |
---|---|
ZADD key score member [[score member]…] | 往有序集合key中加入带分值元素 |
ZREM key member [member …] | 从有序集合key中删除元素 |
ZSCORE key member | 返回有序集合key中元素member的分值 |
ZINCRBY key increment member | 为有序集合key中元素member的分值加上increment |
ZCARD key | 返回有序集合key中元素个数 |
ZRANGE key start stop [WITHSCORES] | 正序获取有序集合key从start下标到stop下标的元素 |
ZREVRANGE key start stop [WITHSCORES] | 倒序获取有序集合key从start下标到stop下标的元素 |
zset的基本使用
> ZADD books 9.0 "think in java"
> ZADD books 8.9 "java concurrency"
> ZADD books 8.6 "java cookbook"> ZRANGE books 0 -1 # 按 score 排序列出,参数区间为排名范围
1) "java cookbook"
2) "java concurrency"
3) "think in java"> ZREVRANGE books 0 -1 # 按 score 逆序列出,参数区间为排名范围
1) "think in java"
2) "java concurrency"
3) "java cookbook"> ZCARD books # 相当于 count()
(integer) 3> ZSCORE books "java concurrency" # 获取指定 value 的 score
"8.9000000000000004" # 内部 score 使用 double 类型进行存储,所以存在小数点精度问题> ZRANK books "java concurrency" # 排名
(integer) 1> ZRANGEBYSCORE books 0 8.91 # 根据分值区间遍历 zset
1) "java cookbook"
2) "java concurrency"> ZRANGEBYSCORE books -inf 8.91 withscores # 根据分值区间 (-∞, 8.91] 遍历 zset,同时返回分值。inf 代表 infinite,无穷大的意思。
1) "java cookbook"
2) "8.5999999999999996"
3) "java concurrency"
4) "8.9000000000000004"> ZREM books "java concurrency" # 删除 value
(integer) 1
> ZRANGE books 0 -1
1) "java cookbook"
2) "think in java
zset应用场景
- 实现热搜排行榜
①:点击 “国庆放假” 新闻时,为其分值+1
ZINCRBY hotNews:20190819 1 国庆放假
②:展示当日排行前十
ZREVRANGE hotNews:20190819 0 9 WITHSCORES
③:七日搜索榜单计算
取7天的key求并集放入新的key=hotNews:20190813-20190819中,就得出这7天中的访问量排行榜
ZUNIONSTORE hotNews:20190813-20190819 7
hotNews:20190813 hotNews:20190814… hotNews:20190819
④:展示七日排行前十
根据上边的并集,从新的key=hotNews:20190813-20190819中取出前10名
ZREVRANGE hotNews:20190813-20190819 0 9 WITHSCORES
相关文章:

【Redis学习2】Redis常用数据结构与应用场景
Redis常用数据结构与应用场景 redis中存储数据是以key-value键值对的方式去存储的,其中key为string字符类型,value的数据类型可以是string(字符串)、list(列表)、hash(字典)、set(集合) 、 zset(有序集合)。 这5种数据类型在开发中可以应对大部分场景的…...
踩了大坑:https 证书访问错乱
文章目录一、问题排查及解决问题一:证书加载错乱问题二:DNS 解析污染问题问题三:浏览器校验问题二、终极解决方法2.1 可外网访问域名2.2 只能内网访问域名2.3 内网自动化配置2.4 错误解决一、问题排查及解决 今天遇到这样一个问题࿰…...

大数据技术之Hive(四)分区表和分桶表、文件格式和压缩
一、分区表和分桶表1.1 分区表partitionhive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录,每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择式选择查询所需要的分区,这样的查询效率辉提高很多。1.1.1 分区表基本语…...

环形缓冲区(c语言)
1、概念介绍 在我们需要处理大量数据的时候,不能存储所有的数据,只能先处理先来的,然后将这个数据释放,再去处理下一个数据。 如果在一个线性的缓冲区中,那些已经被处理的数据的内存就会被浪费掉。因为后面的数据只能…...

创建自助服务知识库的指南
在SaaS领域,自助文档是你可以在客户登录你的网站时为他们提供的最灵活的帮助方式,简单来说,一个自助知识库是一个可以帮助许多客户的文档,拥有出色的自助服务知识库,放在官网或者醒目的地方,借助自助服务知…...

分层测试(1)分层测试是什么?【必备】
1. 什么是分层测试? 分层测试是通过对质量问题分类、分层来保证整体系统质量的测试体系。 模块内通过接口测试保证模块质量,多模块之间通过集成测试保证通信路径和模块间交互质量,整体系统通过端到端用例对核心业务场景进行验证,…...

开源ZYNQ AD9361软件无线电平台
(1) XC7Z020-CLG400 (2) AD9363 (3) 单发单收,工作频率400MHz-2.7GHz (4) 发射带PA,最大输出功率约20dbm (5) 接收带LNA,低…...

第四阶段-12关于Spring Security框架,RBAC,密码加密原则
关于csmall-passport项目 此项目主要用于实现“管理员”账号的后台管理功能,主要实现: 管理员登录添加管理员删除管理员显示管理员列表启用 / 禁用管理员 关于RBAC RBAC:Role-Based Access Control,基于角色的访问控制 在涉及…...
JPA——Date拓展之Calendar
Java Calendar 是时间操作类,Calendar 抽象类定义了足够的方法,在某一特定的瞬间或日历上,提供年、月、日、小时之间的转换提供方法 一、获取具体时间信息 1. 当前时间 获取此刻时间的年月日时分秒 Calendar calendar Calendar.getInstance(); int …...

一文吃透 Spring 中的 AOP 编程
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

Apple主推的智能家居是什么、怎么用?一篇文章带你从零完全入门 HomeKit
如果你对智能家居有所了解,那应该或多或少听人聊起过 HomeKit。由 Apple 开发并主推的的 HomeKit 既因为产品选择少、价格高而难以成为主流,又因其独特的优秀体验和「出身名门」而成为智能家居领域的焦点。HomeKit 究竟是什么?能做什么&#…...

SpringCloud系列知识快速复习 -- part 1(SpringCloud基础知识,Docker,RabbitMQ)
SpringCloud知识快速复习SpringCloud基础知识微服务特点SpringCloud常用组件服务拆分和提供者与消费者概念Eureka注册中心原理Ribbon负载均衡原理负载均衡策略饥饿加载Nacos注册中心服务分级存储模型权重配置环境隔离Nacos与Eureka的区别Nacos配置管理拉取配置流程配置热更新配…...

2023上半年北京/上海/广州/深圳NPDP产品经理认证报名
产品经理国际资格认证NPDP是国际公认的唯一的新产品开发专业认证,集理论、方法与实践为一体的全方位的知识体系,为公司组织层级进行规划、决策、执行提供良好的方法体系支撑。 【认证机构】 产品开发与管理协会(PDMA)成立于1979年…...

面试半年,总结了1000道2023年Java架构师岗面试题
半年前还在迷茫该学什么,怎样才能走出现在的困境,半年后已经成功上岸阿里,感谢在这期间帮助我的每一个人。 面试中总结了1000道经典的Java面试题,里面包含面试要回答的知识重点,并且我根据知识类型进行了分类…...
通过MySQL驱动拦截器实现执行sql耗时计算
文章目录背景具体实现MySQL5MySQL6MySQL8使用方法测试结果背景 公司的一个需求,公司既有的链路追踪日志组件要支持MySQL的sql执行时间打印,要实现链路追踪常用的手段就是实现第三方框架或工具提供的拦截器接口或者是过滤器接口,对于MySQL也不…...

易基因|独家分享:高通量测序后的下游实验验证方法——DNA甲基化篇
大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。此前,我们分享了DNA甲基化研究的测序数据挖掘思路(点击查看详情),进而鉴定出研究的目的基因或目标区域的DNA甲基化。做完测序后,…...
java基础系列(七) 同步和异步理解
一. 问题描述 同步传输和异步传输是web和数据库的重要知识点,会被很多老师强调。那么,它们有什么相同点和不同点?它们对于我们学习编程的意义在哪里? 二. 概念 首先什么是同步和异步? 这里的同步是指&…...
吉林大学 程序设计基础 2022级 OJ期末考试 2.23
本人能力有限,发出只为帮助有需要的人。 以下为实验课的复盘,内容会有大量失真,请多多包涵。 1.双手剑士的最优搭配 每把剑有攻击力和防御力两个属性。双手剑士可以同时拿两把剑,其得到攻击力为两把剑中的攻击力的最大值&#…...
【项目实战】SpringMVC拦截器实战 - 自定义拦截器防止重复提交
一、背景说明 如何能够实现防止重复提交呢?以下是一种可选的方式。 二、代码实战 2.1 注册重复提交拦截器到SpringMVC中 @Configuration @AllArgsConstructor public class ResourcesConfig implements WebMvcConfigurer {private final RepeatSubmitInterceptor repeatSu…...

C++ STL:容器 Container
文章目录1、序列容器1.1、容器共性1.2、vectorvector 结构* vector 扩容原理* vector 迭代器失效1.3、dequedeque 结构deque 迭代器deque 模拟连续空间1.4、listlist 特殊操作list 结构list 迭代器2、关联式容器2.1、容器共性2.2、容器特性3、无序关联式容器3.1、容器共性3.2、…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...