首页 > 数据库 >redis基础

redis基础

时间:2024-09-16 20:19:42浏览次数:10  
标签:redis 基础 value 获取 key print Redis

一.前言

我们前几篇文章说了mysql的基础,不是很深入,但是在我们开发中绝对够用,这篇文章我们来讲我们的redis,我们先来介绍一下我们的redis顺便介绍一下我们的nosql。

在Web应用发展的初期,那时关系型数据库受到了较为广泛的关注和应用,原因是因为那时候Web站点基本上访问和并发不高、交互也较少。而在后来,随着访问量的提升,使用关系型数据库的Web站点多多少少都开始在性能上出现了一些瓶颈,而瓶颈的源头一般是在磁盘的I/O上。而随着互联网技术的进一步发展,各种类型的应用层出不穷,这导致在当今云计算、大数据盛行的时代,对性能有了更多的需求,主要体现在以下几个方面:

  1. 低延迟的读写速度:应用快速地反应能极大地提升用户的满意度

  2. 支撑海量的数据和流量:对于搜索这样大型应用而言,需要利用PB级别的数据和能应对百万级的流量

  3. 大规模集群的管理:系统管理员希望分布式应用能更简单的部署和管理

关系型数据库(RMDBS)与非关系型数据库(NoSQL)的对比:  

数据库中表与表的数据之间存在某种关联的内在关系,因为这种关系,所以我们称这种数据库为关系型数据库。典型:Mysql/MariaDB、postgreSQL、Oracle、SQLServer、DB2、Access、SQLlite3。特点:

  1. 全部使用SQL(结构化查询语言)进行数据库操作。

  2. 都存在主外键关系,表,等等关系特征。

  3. 大部分都支持各种关系型的数据库的特性:事务、存储过程、触发器、视图、临时表、模式、函数

NOSQL:not only sql,泛指非关系型数据库。泛指那些不使用SQL语句进行数据操作的数据库,所有数据库中只要不使用SQL语句的都是非关系型数据库。典型:Redis、MongoDB、hbase、 Hadoop、elasticsearch、图数据库(Neo4j、GraphDB、SequoiaDB)

二.redis介绍 

2.1 定义

redis的出现主要是为了替代早期的Memcache缓存系统的。map内存型(数据存放在内存中)的非关系型(nosql)key-value(键值存储)数据库, 支持数据的持久化(基于RDB和AOF,注: 数据持久化时将数据存放到文件中,每次启动redis之后会先将文件中数据加载到内存,经常用来做缓存、数据共享、购物车、消息队列、计数器、限流等。(最基本的就是缓存一些经常用到的数据,提高读写速度)。

redis特性:

  • 速度快

  • 持久化

  • 多种数据结构

  • 支持多种编程语言

  • 主从复制

  • 高可用、分布式  

 2.2 redis的数据类型和主要特征

Redis提供的数据类型主要分为5种自有类型和一种自定义类型,这5种自有类型包括:String类型、哈希类型、列表类型、集合类型和顺序集合类型。

redis={
"name":"yuan",
"age":"23",
"scors":[78,79,98,],
"info":{"gender":"male","tel":"110"},
"set":{1,2,3},
"zset":{1,2,3,}
}

2.3 redis的应用场景有哪些

Redis 的应用场景包括:

缓存系统(“热点”数据:高频读、低频写):缓存用户信息,优惠券过期时间,验证码过期时间、session、token等

计数器:帖子的浏览数,视频播放次数,评论次数、点赞次数等

消息队列,秒杀系统

社交网络:粉丝、共同好友(可能认识的人),兴趣爱好(推荐商品)

排行榜(有序集合)

发布订阅:粉丝关注、消息通知

然后安装我就不和大家说了,直接给网址

Releases · tporadowski/redis · GitHubNative port of Redis for Windows. Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs. This repository contains unofficial port of Redis to Windows. - Releases · tporadowski/redisicon-default.png?t=O83Ahttps://github.com/tporadowski/redis/releases  下载好一路下一步就行了

安装好之后我们打开cmd,输入redis-sever 当然win的同学不用执行这一步,因为redis在win上默认启动,然后输入redis-cli就是启动数据库

这样就是使用成功了,这里就不给大家配置了,但是注意的是redis一共有16个库,分别是0-15号库,每个库不互通

2.4 切换数据库

前面说了 redis的配置文件中,默认有0~15之间的16个数据库,默认操作的就是0号数据库

那这里我单独拿出来讲我们今天的第一个命令

select <数据库ID>

 

三.redis的数据类型

redis可以理解成一个全局的大字典,key就是数据的唯一标识符。根据key对应的值不同,可以划分成5个基本数据类型。

redis = {
    "name":"yuan",
    "scors":["100","89","78"],
    "info":{
        "name":"rain"
        "age":22
    },
    "s":{item1,itme2,..}
}

1. string类型:
    字符串类型,是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,也就是byte类型。
    单个数据的最大容量是512M。
        key: 值
2. hash类型:
    哈希类型,用于存储对象/字典,对象/字典的结构为键值对。key、域、值的类型都为string。域在同一个hash中是唯一的。
        key:{
            域(属性): 值,
            域:值,            
            域:值,
            域:值,
            ...
        }
3. list类型:
    列表类型,它的子成员类型为string。
        key: [值1,值2, 值3.....]
4. set类型:
    无序集合,它的子成员类型为string类型,元素唯一不重复,没有修改操作。
        key: {值1, 值4, 值3, ...., 值5}

5. zset类型(sortedSet):
    有序集合,它的子成员值的类型为string类型,元素唯一不重复,没有修改操作。权重值(score,分数)从小到大排列。
        key: {
            值1 权重值1(数字);
            值2 权重值2;
            值3 权重值3;
            值4 权重值4;
        }

3.1 字符串

  • SET/SETEX/MSET/MSETNX

  • GET/MGET

  • GETSET

  • INCR/DECR

  • DEL

 3.1.1 设置键值

set key value

 注意:redis中的所有数据操作,如果设置的键不存在则为添加,如果设置的键已经存在则修改。

 3.1.2 设置键值的过期时间

setex key seconds value

 

 3.1.3 设置多个键值

mset key1 value1 key2 value2 ...

 

 3.1.4 字符串拼接 

常见于大文件上传

append key value 

 

3.1.5 根据键获取值

根据键获取值,如果不存在此键则返回nil

get key 

根据多个键获取多个值

mget key1 key2 ... 

 

 3.1.5 自增自减

web开发中的电商抢购、秒杀。游戏里面的投票、攻击计数。系统中计算当前在线人数

incr key    自增

decr key   自减

incrby key num 自增num

decrby key num 自减num

 

3.1.6 获取字符串长度

 strlen key

 

3.1.7 比特流操作

mykey 00000011

1字节=8比特 1kb = 1024字节 1mb = 1024kb 1gb = 1024mb

1个int8就是一个字节,一个中文:3个字节  

SETBIT     # SETBIT key offset value 按从左到右的偏移量设置一个bit数据的值 
GETBIT     # 获取一个bit数据的值
BITCOUNT   # 统计字符串被设置为1的bit数.
BITPOS     # 返回字符串里面第一个被设置为1或者0的bit位。 

 

这个我用的也不是很熟练,但是在优化的时候用的多

案例一:将字符串a变成b

我们知道 'a' 的ASCII码是 97。转换为二进制是:01100001。offset的学名叫做“偏移” 。二进制中的每一位就是offset值啦,比如在这里 offset 0 等于 ‘0’ ,offset 1等于 '1' ,offset 2 等于 '1',offset 6 等于 '0' ,没错,offset是从左往右计数的,也就是从高位往低位

也就是将 01100001 变成 01100010 (b的ASCII码是98),这个很简单啦,也就是将'a'中的offset 6从0变成1,将offset 7 从1变成0  

案例二:签到系统

setbit user_1 6 1
setbit user_1 5 1
setbit user_1 4 0
setbit user_1 3 1
setbit user_1 2 0
setbit user_1 1 1
setbit user_1 0 1
BITCOUNT user_1 # 统计一周的打卡情况 

我们可以通过比特位来操作 这样可以大大节约内存

3.2 key操作

3.2.1 查找key

查找支持正则表达式

keys pattern 

 

keys * 就是查看所有的key

3.2.2 判断key是否存在

exists key 

 

返回1就是存在

3.2.3 查看键的值的类型

type key

# string    字符串
# hash      哈希类型
# list      列表类型
# set       无序集合
# zset      有序集合

 

 3.2.4 删除键以及键对应的值

del key1 key2 ... 

 

删除成功返回1,失败返回0

 3.4.5 查看键的的有效期

ttl key

# 结果结果是秒作为单位的整数
# -1 表示永不过期
# -2 表示当前数据已经过期,查看一个不存在的数据的有效期就是-2

3.4.6 设置key的有效期 

给已有的数据重新设置有效期,redis中所有的数据都可以通过expire来设置它的有效期。有效期到了,数据就被删除。

expire key seconds 

 

3.4.7 key重命名 

rename  oldkey newkey 

 

3.4.8 清空所有的key

慎用,一旦执行,则redis所有数据库0~15的全部key都会被清除

flushall 

 

3.3 list(数组) 

队列,列表的子成员类型为string

lpush key value

rpush key value

linsert key after|before 指定元素 value

lindex key index

lrange key start stop

lset key index value

lrem key count value  

3.3.1 添加子成员

# 在左侧(前)添加一条或多条数据
lpush key value1 value2 ...
# 在右侧(后)添加一条或多条数据
rpush key value1 value2 ...

# 在指定元素的左边(前)/右边(后)插入一个或多个数据
linsert key before 指定元素 value1 value2 ....
linsert key after 指定元素 value1 value2 ....

 

3.3.2 基于索引获取列表成员

根据指定的索引(下标)获取成员的值,负数下标从右边-1开始,逐个递减  

 lindex key index

 

3.3.3 获取列表的切片

lrange key start stop 

 

 3.3.4 获取列表长度

llen key

 

 3.3.5 按索引设置值

lset key index value
# 注意:
# redis的列表也有索引,从左往右,从0开始,逐一递增,第1个元素下标为0
# 索引可以是负数,表示尾部开始计数,如`-1`表示最后1个元素

 

 3.3.6 删除指定成员

lpop key  # 第一个成员出列
rpop key  # 最后一个成员出列 

 

 3.4 hash(哈希)

hset key field value

hget key field

hgetall info

hmget key field1 field2 ...

hincrby key field number  

 专门用于结构化的数据信息。对应的就是map/结构体

结构:

键key:{
       域field: 值value,
       域field: 值value,
       域field: 值value,
}

3.4.1 设置指定键的属性

 hset key field value

 

可以设置多个,已经有了就算覆盖,没有就算是新建

3.4.2 获取指定键的属性 

获取hash下所有的键

hkeys key 

 

获取指定键的单个域/属性的值

hget key field 

 

获取指定键的多个域/属性的值

hmget key field1 field2 ... 

 

获取指定键的所有值

hvals key 

 

3.4.3 获取hash的所有域值对

hgetall key

 

3.4.4 删除指定键的域/属性

hdel key field1 field2 ...

 

 3.4.5 判断指定属性是否在hash结构中

hexists   key  field

  

 3.4.6 属性值自增自减

hincrby key field number

 

 3.5 set(集合)

无序集合,重点就是去重和无序。

 3.5.1 添加元素

sadd key member1 member2 ...

 

3.5.2 获取集合所有成员

smembers key 

 

 但是这个其实是无序的

3.5.3 获取集合长度

scard keys 

 

3.5.4 随机抽取一个或多个元素 

spop key [count=1]

# 注意:
# count为可选参数,不填则默认一个。被提取成员会从集合中被删除掉

 

3.5.5 删除指定元素

srem key value 

 

3.5.6 交集,差集,并集 

推荐、(协同过滤,基于用户、基于物品)

sinter  key1 key2 key3 ....    # 交集、比较多个集合中共同存在的成员
sdiff   key1 key2 key3 ....    # 差集、比较多个集合中不同的成员
sunion  key1 key2 key3 ....    # 并集、合并所有集合的成员,并去重 

这里我就不和大家展示了,太累了

3.6 zset(有序集合) 

有序集合(score/value),去重并且根据score权重值来进行排序的。score从小到大排列。

3.6.1 添加成员

zadd key score1 member1 score2 member2 score3 member3 ....

 

3.6.2 获取指定区间的成员

zrangebyscore key min max     # 按score进行从低往高排序获取指定score区间
zrevrangebyscore key min max  # 按score进行从高往低排序获取指定score区间
zrange key start stop         # 按scoer进行从低往高排序获取指定索引区间
zrevrange key start stop      # 按scoer进行从高往低排序获取指定索引区间 

这里也就不一一和大家演示了

3.6.3 获取集合长度

zcard key 

 

 3.6.4 获取指定成员的权重值

zscore key member

 

3.6.5 获取指定成员的排名

zrank key member      # score从小到大的排名
zrevrank key member   # score从大到小的排名 

 

 3.6.6 获取score在指定区间的所有成员数量

zcount key min max

 

3.6.7 给指定成员增加权重值

zincrby key score member 

 

3.6.8 删除成员 

zrem key member1 member2 member3 .... 

 

3.6.9 删除指定数量的成员 

# 删除指定数量的成员,从最低score开始删除
zpopmin key [count]
# 删除指定数量的成员,从最高score开始删除
zpopmax key [count] 

 四.python操作redis

4.1 连接redis 

# 方式1
import redis

r = redis.Redis(host='127.0.0.1', port=6379) #db=1 这个就代表使用1库 不写默认0库
r.set('foo', 'Bar')
print(r.get('foo'))


# 方式2 (一般用方式二较多)
import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379) ##db=1 这个就代表使用1库 不写默认0库
r = redis.Redis(connection_pool=pool)
r.set('bar', 'Foo')
print(r.get('bar'))

通常情况下, 当我们需要做redis操作时, 会创建一个连接, 并基于这个连接进行redis操作, 操作完成后, 释放连接,一般情况下, 这是没问题的, 但当并发量比较高的时候, 频繁的连接创建和释放对性能会有较高的影响。于是, 连接池就发挥作用了。连接池的原理是, 通过预先创建多个连接, 当进行redis操作时, 直接获取已经创建的连接进行操作, 而且操作完成后, 不会释放, 用于后续的其他redis操作。这样就达到了避免频繁的redis连接创建和释放的目的, 从而提高性能。  

4.2 数据操作

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, db=0, decode_responses=True)
r = redis.Redis(connection_pool=pool)

# (1)字符串操作:不允许对已经存在的键设置值
ret = r.setnx("name", "yuan")
print(ret)  # False
# (2)字符串操作:设置键有效期
r.setex("good_1001", 10, "2")
# (3)字符串操作:自增自减
r.set("age", 20)
r.incrby("age", 2)
print(r.get("age"))  # b'22'

# (4)hash操作:设置hash
r.hset("info", "name", "rain")
print(r.hget("info", "name"))  # b'rain'
r.hmset("info", {"gedner": "male", "age": 22})
print(r.hgetall("info"))  # {b'name': b'rain', b'gender': b'male', b'age': b'22'}

# (5)list操作:设置list
r.rpush("scores", "100", "90", "80")
r.rpush("scores", "70")
r.lpush("scores", "120")
print(r.lrange("scores", 0, -1))  # ['120', '100', '90', '80', '70']
r.linsert("scores", "AFTER", "100", 95)
print(r.lrange("scores", 0, -1))  # ['120', '100', '95', '90', '80', '70']
print(r.lpop("scores"))  # 120
print(r.rpop("scores"))  # 70
print(r.lindex("scores", 1)) # '95'

# (6)集合操作
# key对应的集合中添加元素
r.sadd("name_set", "zhangsan", "lisi", "wangwu")
# 获取key对应的集合的所有成员
print(r.smembers("name_set"))  # {'lisi', 'zhangsan', 'wangwu'}
# 从key对应的集合中随机获取 numbers 个元素
print(r.srandmember("name_set", 2))
r.srem("name_set", "lisi")
print(r.smembers("name_set"))  # {'wangwu', 'zhangsan'}

# (7)有序集合操作
# 在key对应的有序集合中添加元素
r.zadd("jifenbang", {"yuan": 78, "rain": 20, "alvin": 89, "eric": 45})
# 按照索引范围获取key对应的有序集合的元素
# zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)
print(r.zrange("jifenbang", 0, -1))  # ['rain', 'eric', 'yuan', 'alvin']
print(r.zrange("jifenbang", 0, -1, withscores=True))  # ['rain', 'eric', 'yuan', 'alvin']
print(r.zrevrange("jifenbang", 0, -1, withscores=True))  # ['rain', 'eric', 'yuan', 'alvin']

print(r.zrangebyscore("jifenbang", 0, 100))
print(r.zrangebyscore("jifenbang", 0, 100, start=0, num=1))

# 删除key对应的有序集合中值是values的成员
print(r.zrem("jifenbang", "yuan"))  # 删除成功返回1
print(r.zrange("jifenbang", 0, -1))  # ['rain', 'eric', 'alvin']

# (8)键操作
r.delete("scores")
print(r.exists("scores"))
print(r.keys("*"))
r.expire("name",10)

发现python的api和redis命令差不多,大家做个了解就行,会redis就会这个了

4.3 队列的监听和发布消息

subscribe key 监听

publish key message 发布

 

 

 如图所示,这样就是监听和发布消息

五.redis的实战案例

5.1 KV缓存

我们可以用Redis来缓存用户信息、会话信息、商品信息等等。下面这段代码就是通过缓存读取逻辑

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, db=6, decode_responses=True)
r = redis.Redis(connection_pool=pool)


def get_user(user_id):
    user = r.get(user_id)
    if not user:
        user = UserInfo.objects.get(pk=user_id)
        r.setex(user_id, 3600, user)

    return user

5.2 分布式锁 

问:什么是分布式锁

分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的系统或同一个系统的不同主机之间共享了某个临界资源,往往需要互斥来防止彼此干扰,以保证一致性。  

即先用setnx来抢锁,如果抢到之后,再用expire给锁设置一个过期时间,防止锁忘记了释放  

假设某电商网站的某商品做秒杀活动,key可以设置为key_resource_id,value设置任意值,伪代码如下:

方案1:

import redis

pool = redis.ConnectionPool(host='127.0.0.1')
r = redis.Redis(connection_pool=pool)
ret = r.setnx("key_resource_id", "ok")
if ret:
    r.expire("key_resource_id", 5)  # 设置过期时间
    print("抢购成功!")
    r.delete("key_resource_id")  # 释放资源
else:
    print("抢购失败!")

但是这个方案中,setnxexpire两个命令分开了,「不是原子操作」。如果执行完setnx加锁,正要执行expire设置过期时间时,进程crash或者要重启维护了,那么这个锁就“长生不老”了,「别的线程永远获取不到锁啦」

方案二:SETNX + value值是(系统时间+过期时间)

为了解决方案一,「发生异常锁得不到释放的场景」,可以把过期时间放到setnx的value值里面。如果加锁失败,再拿出value值校验一下即可。加锁代码如下:

import time


def foo():
    expiresTime = time.time() + 10
    ret = r.setnx("key_resource_id", expiresTime)
    if ret:
        print("当前锁不存在,加锁成功")
        return True

    oldExpiresTime = r.get("key_resource_id")
    if float(oldExpiresTime) < time.time():  # 如果获取到的过期时间,小于系统当前时间,表示已经过期
        # 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间
        newExpiresTime = r.getset("key_resource_id", expiresTime)
        if oldExpiresTime == newExpiresTime:
            #  考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才可以加锁
            return True  # 加锁成功

    return False  # 其余情况加锁皆失败


foo()

方案三:

实际上,我们还可以使用Py的redis模块中的set函数来保证原子性(包含setnx和expire两条指令)代码如下:

r.set("key_resource_id", "1", nx=True, ex=10)

5.3 延迟队列 

延时队列可以通过Redis的zset(有序列表)来实现。我们将消息序列化为一个字符串作为zset的值。这个消息的到期时间处理时间作为score,然后用多个线程轮询zset获取到期的任务进行处理,多线程时为了保障可用性,万一挂了一个线程还有其他线程可以继续处理。因为有多个线程,所有需要考虑并发争抢任务,确保任务不能被多次执行。

 

import time
import uuid

import redis

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True)
r = redis.Redis(connection_pool=pool)


def delay_task(task_name, delay_time):
    # 保证value唯一
    task_id = task_name + str(uuid.uuid4())

    retry_ts = time.time() + delay_time
    r.zadd("delay-queue", {task_id: retry_ts})


def loop():
    print("循环监听中...")
    while True:
        # 最多取1条
        task_list = r.zrangebyscore("delay-queue", 0, time.time(), start=0, num=1)

        if not task_list:
            # 延时队列空的,休息1s
            print("cost 1秒钟")
            time.sleep(1)
            continue
        task_id = task_list[0]
        success = r.zrem("delay-queue", task_id)
        if success:
            # 处理消息逻辑函数
            handle_msg(task_id)

def handle_msg(msg):
    """消息处理逻辑"""
    print(f"消息{msg}已经被处理完成!")


import threading

t = threading.Thread(target=loop)
t.start()

delay_task("任务1延迟5", 5)
delay_task("任务2延迟2", 2)
delay_task("任务3延迟3", 3)
delay_task("任务4延迟10", 10)

redis的zrem方法是对多线程争抢任务的关键,它的返回值决定了当前实例有没有抢到任务,因为loop方法可能会被多个线程、多个进程调用, 同一个任务可能会被多个进程线程抢到,通过zrem来决定唯一的属主。同时,一定要对handle_msg进行异常捕获, 避免因为个别任务处理问题导致的循环异常退出。

5.4  发布订阅

subscribe channel # 订阅
publish channel mes # 发布消息

这个就是前面说的队列的监听和发布

import threading

import redis

r = redis.Redis(host='127.0.0.1')


def recv_msg():
    pub = r.pubsub()

    pub.subscribe("fm104.5")
    pub.parse_response()

    while 1:
        msg = pub.parse_response()
        print(msg)


def send_msg():
    msg = input(">>>")
    r.publish("fm104.5", msg)


t = threading.Thread(target=send_msg)
t.start()

recv_msg()

 5.5 定时任务

利用 Redis 也能实现订单30分钟自动取消。

用户下单之后,在规定时间内如果不完成付款,订单自动取消,并且释放库存使用技术:Redis键空间通知(过期回调)用户下单之后将订单id作为key,任意值作为值存入redis中,给这条数据设置过期时间,也就是订单超时的时间启用键空间通知

开启过期key监听

from redis import StrictRedis

redis = StrictRedis(host='localhost', port=6379)

# 监听所有事件
# pubsub = redis.pubsub()
# pubsub.psubscribe('__keyspace@0__:*')
#
# print('Starting message loop')
# while True:
#     message = pubsub.get_message()
#     if message:
#         print(message)

# 监听过期key
def event_handler(msg):
    print("sss",msg)
    thread.stop()

pubsub = redis.pubsub()
pubsub.psubscribe(**{'__keyevent@0__:expired': event_handler})
thread = pubsub.run_in_thread(sleep_time=0.01)

六.总结 

 大家可以发现我这个讲的非常细,分类也细致,希望大家可以消化吸收,当我们能够知道redis的使用作用的时候,在后续开发中能够想到,我认为就是可以了

七.补充

有什么问题私我,记得点赞关注加收藏哦,有求必应,有什么需求已经想要学习资料都能看我名字 

 

标签:redis,基础,value,获取,key,print,Redis
From: https://blog.csdn.net/weixin_74178589/article/details/142290078

相关文章

  • 三、redis之strings类型
    strings是redis中使用最多的类型。redis官网中是这么描述strings的:Redisstringsstoresequencesofbytes,includingtext,serializedobjects,andbinaryarrays.可以看到Redisstrings保存的是sequencesofbytes,也就是字节序列。不仅可以保存字符串,而且还可以保存二......
  • JAVA 多线程基础:JAVA中double 和 long非原子读写问题
    在解释这个问题之前,我们先来回顾下Java中基础数据类型所占的位数。类型长度(位)字节byte41boolean41int324short162long648char162float324double648可以看到对于double以及long两种基本数据类型,所占位数为64位。而JVM却有32bit与64bit两种,也就是说在32bitJVM中不能将doub......
  • jsp城市公共基础医疗o928f
    jsp城市公共基础医疗o928f本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能员工,培训信息,考核成绩,公告信息,场所信息,卫生监控,废弃物处理,健康信息开题报告内容一、项目背景与意义随着城市化进......
  • Linux 基础入门操作-实验二 makefile使用介绍 和 实验三 hello 输出
    1介绍Makefile是linux下的项目管理工具,想象一下当有很多源文件需要编译、链接时,你只需执行make命令即可完成编译操作,这样是不是很方便呢。make命令执行时,需要一个Makefile文件,用来告诉make命令需要怎么样的去编译和链接程序,下面详细介绍Makefile的使用与书写规......
  • 前端工程化学习笔记-02(webpack基础用法)
    前端工程化学习笔记-02(webpack基础用法)webpack基础用法快速搭建一个简易的webpack项目使用npminit初始化一个项目;mkdirwebpack-democdwebpack-demonpminit-y本地安装webpack;npminstallwebpackwebpack-cli--save-dev修改package.json文件#删除"main"......
  • 代码随想录算法训练营Day5 | 哈希表理论基础、242.有效的字母异位词、349.两个数组的
    哈希表理论基础哈希表哈希表是根据关键码的值而直接进行访问的数据结构。数组就是一张哈希表,哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素,如下图所示:哈希表一般用来快速判断一个元素是否出现集合里。哈希函数哈希函数通过特定编码方式,可以将其......
  • 深入理解redis删除策略和淘汰策略
    1、redis的删除策略Redis是一种内存级数据库,数据都存在内存中,但是针对于已经过期的数据,reids不会立刻删除只是会存储在 expires 中,当执行删除策略的时候,才会从expires中寻找对应的数据存储的地址,在存储空间中找到对应的数据进行删除。数据删除其实就是内存和CPU占用之间寻......
  • 深入理解Redis锁与Backoff重试机制在Go中的实现
    目录Redis锁的深入实现Backoff重试策略的深入探讨结合Redis锁与Backoff策略的高级应用具体实现结论在构建分布式系统时,确保数据的一致性和操作的原子性是至关重要的。Redis锁作为一种高效且广泛使用的分布式锁机制,能够帮助我们在多进程或分布式环境中同步访问共享资源。本文将深......
  • C++数据结构-二叉树的存储方法(基础篇)
    1.简介根据前文的介绍,我们知道了二叉树的性值,其就是一种每一个结点中只允许拥有左右孩子(或为空)的树,这种数据结构在我们的实际设计中非常常用,如前文提到的STL中的set集合,其底层就是一颗标准的红黑树(二叉树的一种),我们这里以创建一颗二叉树并实现通过特定的插入顺序和读取顺序达......
  • 【python】python入门基础理论+实践,这一篇就够了
    简介:第一个helloworldprint("helloworld!");foriinrange(10):print('run:',i);importtime;time.sleep(10);字符串str在Python中,加了引号的字符都被认为是字符串!name="zhangsan"多引号多引号什么作⽤呢?作⽤就是多⾏字符串必须⽤多引号message='''这......