redis学习 + go-redis 基本使用
安装
官网下载redis包,用xftp传输到Linux的 /opt 文件夹下
安装C语言编译环境
yum install centos-releases-scl scl-utils-build
yum install -y devtoolset-8-toolchain
scl enable devtoolset-8 bash
安装gcc
yum install gcc
解压redis
tar -zxvf redis-6.2.7.tar.gz
进入解压后的文件夹,进行编译
make
安装
make install
redis会默认安装在/usr/local/bin
目录下
redis-benchmark:性能测试工具
redis-check-aof :修复有问题的AOF文件
redis-check-rdb :修复有问题的dump.rdb文件
redis-sentinel :Redis集群使用
redis-server:Redis服务器启动命令
redis-cli :客户端,操作入口
启动
前台启动
直接使用redis-server
进行前台启动,占用掉当前控制台
ctrl+c
退出
后台启动
拷贝redis编译目录下的redis.conf
文件到/etc/redis.conf
然后修改etc目录下redis.conf,将 daemonize no
改成 daemonize yes
(保存时记得用:wq!
)daemonize: 后台运行
之后回到安装目录/usr/local/bin
执行
redis-server /etc/redis.conf
(如果仍然前台执行,检查一下上一步是否成功,这种叫指定配置启动)
执行成功后,通过
ps -ef | grep redis
查找端口信息
之后便可通过客户端连接
redis-cil
Redis关闭的话就用shutdown
或者exit
退出后用kill -9 PID
来结束进程
相关知识
默认端口号:6379
默认16个数据库,从0到15,默认使用0号库
连接到客户端后,使用select 1
来切换到1号库
redis
单线程+IO多路复用
select 1
来切换到1号库dbsize
查看当前库的键数目flushdb
来清空当前库flushall
清空所有库
五大基本数据类型
Redis字符串(String)
可存放任何字符串内容(包括字符化的图片),最大字符串512M
查看所有键:
keys *
添加或修改一个键:
set key value
添加或修改多个键:
mset key1 value1 key2 value2 ...
添加一个键:
setnx <key> <value>
添加多个键:
msetnx key1 value1 key2 value2 ...
原子操作,如果有一个失败,其它都创建失败删除一个键:
del key
异步删除一个键:
unlink key
获取一个键:
get key
获取多个键:
mget key1 key2 key3
判断该键是否存在:
exists key
1 为存在 0 为不存在查看该键类型:
type key
设置键的过期时间:
exipire key seconds(秒数)
过期后自动删除查看该键过期时间:
ttl key
-2为已过期(或不存在), -1为永不过期创建有过期时间的键值对:
setex <key> 过期时间 <value>
获取原值并设置新值:
getset key value
get <key>
获取键对应的值append <key> <value>
给值后追加内容,如果原键值对不存在,则会新建一个键值对strlen <key>
获取值的长度setnx <key> <value>
只有当键值对不存在时,才能成功设置键值对incr <key>
给该纯数字值自增1incrby <key> count
给该纯数字自增countdecr <key>
给该纯数字值自减1decrby <key> count
给该纯数字值自减countgetrange key 0 3
获取值的0-3位(包括0和3)setrange key 开始位置 value
从开始位置开始覆写值
Redis 列表(List)
一键多值
lpush/rpush <key> <value1> <value2> ...
从列表左边或者右边插入一个或多个值lpop/rpop <key>
从列表左边或列表右边弹出一个值rpoplpush <key1> <key2>
从key1右边弹出一个值,并将这个值添加到key2的左边lrange <key> <start> <end>
按照索引下标获得元素lrange mylist 0 -1
获取该列表所有元素
lindex <key> <index>
按照下标获取元素(从左到右)llen <key>
获取列表长度linsert <key> before/after <value> <newvalue>
在从左到右第一个 value 前/后 插入<newvalue>
lrem <key> <n> <value>
从左边开始,删除n个value值lset <key> <index> <value>
将列表key下标为index的值替换为value
数据少时,由连续分配内存空间的ziplist
线性表构成
当数据量多的时候,数据会存放在多个ziplist
中,由链表将其链接
set集合
string类型的无序集合,底层为value为null的hash表
sadd <key> <value1> <value2> <value3>
将一个或多个member元素添加到集合key中,已存在的忽略掉smembers <key>
取出该集合的所有值sismember <key><value>
判断集合key中是否含有该value值,有1,无0scard <key>
返回该集合元素个数srem <key> <value1> <value2> ...
删除集合中某个元素spop <key>
随机从该集合中吐出一个值srandmember <key> <n>
随机从该集合中取出n个值smove <source> <destination> value
把集合中的一个值从一个集合移动到另一个集合- 例如:
smove k1 k2 v100
把集合k1的值v100移动到k2集合
- 例如:
sinter <key1> <key2>
返回两个集合的交集元素sunion <key1> <key2>
返回两个集合的并集元素sdiff <key1> <key2>
返回两个集合的差集元素(k1中有但k2中没有的元素)
set数据结构是dict字典,字典使用哈希表实现
Redis 哈希(Hash)
键值对集合,string类型的field和value映射表
hset <key> <field> <value>
给key集合中的field键赋值valuehget <key1> <field>
从key1集合取出field的值hmset <key1> <field1> <value1> <field2> <value2> ...
批量设置hash的值hexists <key1> <field>
判断哈希表key1中,给定域field是否存在hkeys <key>
列出该hash集合中所有的fieldhvals <key>
列出该hash集合中所有的valuehincrby <key> <field> <increment>
为哈希表key中的域field的值加上增量 increment(负数也行)hsetnx <key> <field> <value>
将哈希表key中的域field值设置为value,当且仅当field不存在
当field-value长度短且个数少时,使用ziplist,否则使用hashtable
Redis 有序集合Zset
没有重复元素的有序字符串集合,按score从小到大排序
zadd <key> <score1> <value1> <score2> <value2> ...
将一个或多个member元素及其score加入到有序集key中zrange <key> <start> <stop> [withscores]
返回有序集中,下标在start和stop之间的元素带withscores,可以让score一起和值返回到结果集
zrangebyscore key min max [withscores][limit offset count]
返回有序集key中,所有score介于min和max之间(包括min和max)的成员,有序成员按score从小到大排序zrevrangebyscore key max min [withscores][limit offset count]
同上,输出顺序改为由大到小zincrby <key> <increment> <value>
让元素的score自增incrementzrem <key> <value>
删除该集合下的指定元素zcount <key> <min> <max>
统计该集合,min和max区间内元素个数zrank <key> <value>
返回该值在集合中的排名,从0开始
zset使用两个数据结构
- hash:用来关联元素value和权重score
- 跳跃表:给元素value排序,根据score范围获取元素列表
配置文件
之前在做后台启动时将其放到了/etc/redis.conf
下
配置文件内 75行的
bind 127.0.0.1 -::1
表示只能通过本地连接,如果需要通过其它电脑远程连接,需要将其注释掉(前面加#)94行的
protected-mode yes
表示本机访问保护模式,如果需要远程访问,将yes改为noport 6379
端口号tcp-backlog 511
tcp的backlog连接队列,是未完成三次握手队列和已完成三次握手队列总和timeout 0
超时断开,默认0秒tcp-keepalive 300
存活检测,300秒检测一次,如果没有操作,释放连接
GENERAL
####################################### GENERAL########################################daemonize yes
是否允许后台启动pidfile
运行进程文件loglevel notice
日志级别logfile ""
日志文件输出路径databases 16
库数量
SECURITY安全
密码一定要设置,之前看B站评论区,一大堆人服务器被挖矿
################################ SECURITY ##################################
找到大概903行
# requirepass foobared
取消该行的注释 foobared就是密码,
之后重启redis
连接redis后,使用
auth 密码
来验证
Limit
maxclients
设置redis同时可以与多少个客户端连接,默认10000
maxmemory
设置redis可以使用的内存量,建议必须设置,一旦达到内存上限,则会试图移除内部数据,移除规则通过maxmemory-policy来指定
发布和订阅
发布者发布消息,订阅者接受消息
Redis客户端可以订阅多个频道
发布订阅命令行实现
打开两个会话窗口,都连接下redis
第一个会话窗口做订阅者,
subscribe channel1 # 订阅 channel1
第二个会话窗口做发布者
publish channel1 hello # 向 channel1 发送消息 hello
Redis6新数据类型
Bitmaps
存储bit的key
setbit key offset value
添加/修改 该key 的一个位移量的值getbit key offset
获取该key 位移量处的值bitcount key [start end]
统计该key值为 1 的个数start和end用数字表示,但是数字表示的是第几个字节,每个字节包括8位bit
bitop operation destkey key [key ...]
operation: and(与)、or(或 )、not(非)、xor(异或) 操作并将结果保存在的destkey中
HyperLogLog
适用于大量元素计算基数,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2642^{64}264个不同元素的基数
根据输入元素计算基数(不重复元素个数),而不会存储输入元素本身
pfadd <key> <element> [element ...]
添加指定元素到HyperLogLog中pfcount <key> [key ...]
计算key的基数pfmerge <destkey> <sourcekey> [sourcekey ...]
将一个或多个HLL合并后的结果存储到destkey中
Geospatial
GEO Geophysic 地理信息的缩写,该类型就是元素的二维坐标
geoadd key longitude latitude member [longitude latitude member ...]
添加地理位置(经度,纬度,名称)有效精度从-180度到180度。有效维度从-85.05112878到85.05112878,已添加的数据无法再次添加
geopos <key> <member> [member...]
获得指定地区的坐标值geodist <key> <member1><member2> [m|km|ft|mi]
获取两个位置之间的直线距离georadius <key> <longitude> <latitude> radius m|km|ft|mi
以给定的经纬度为中心,找出某一半径内的元素
设置redis开机自启
要保证配置文件中daemonize yes
而不是no
daemonize : 后台运行
新建一个系统服务文件 :
vim /etc/systemd/system/redis.service
然后,将下面的内容写入到系统服务文件中:
[Unit]
Description=redis-server
After=network.target[Service]
Type=forking# 这行配置内容要根据redis的安装目录自定义路径
ExecStart=/usr/local/bin/redis-server /etc/redis.conf
PrivateTmp=true[Install]
WantedBy=multi-user.target
执行下面的命令,实现开机自启:
systemctl enable redis
保存系统服务文件,然后输入命令,重载系统服务:
systemctl daemon-reload
查看此时,redis 服务的状态:
systemctl status redis
go-redis
安装
直接在项目开头引入该库
import("github.com/go-redis/redis"
)
执行
go mod tidy
即可
连接redis
首先初始化一个全局Client指针变量
var rdb *redis.Client
之后初始化连接
func initClient() (err error){rdb = redis.NewClient(&redis.Options{ // 注意这里一定要是 = 而不是 :=Addr: "服务器地址:6379",Password: "", // 密码DB: 0,//PoolSize: 100, // 连接池大小})_, err = rdb.Ping().Result()return err
}
到这里后先进行一个测试
func main(){if err := initClient(); err != nil {fmt.Printf("init redis client failed, err:%v\n", err)return}fmt.Println("connect redis success...")// 释放相关资源defer rdb.Close()
}
如果输出结果为"connect redis success…"则连接成功
但如果报错: I/O timeout,请从以下几个地方寻找错误原因
redis的配置文件中,只允许本地连接的
bind 127.0.0.1 -::1
是否注释掉redis的配置文件中,本机访问保护模式
protected-mode yes
是否改为protected-mode no
如果使用虚拟机进行的学习,看防火墙是否关闭
systemctl status firewalld
如果没关闭,使用
systemctl stop firewalld
关闭防火墙
systemctl disable firewalld
禁止防火墙开机自启
基本使用
基本上,获取某个值时,都可以通过在函数后加上.Result()
或.Val()
来仅获取结果,不输出操作名称
例如:
fmt.Println(rdb.get("name")) // get name : rzzy
fmt.Println(rdb.get("name").Val()) // rzzy
package mainimport ("fmt""github.com/go-redis/redis""time"
)// 声明一个全新的rdb变量
var rdb *redis.Client// 初始化连接
func initClient() (err error) {rdb = redis.NewClient(&redis.Options{Addr: "服务器地址:6379",Password: "", // 密码DB: 0,//PoolSize: 100, // 连接池大小})_, err = rdb.Ping().Result()return err
}// 字符串以及一些键值对的基本操作
func stringEx() {// 添加/修改一个键err := rdb.Set("name", "rzzy", 0).Err()if err != nil {fmt.Printf("set err,err:%v\n", err)return}// 查看所有键fmt.Println("所有键:", rdb.Keys("*").Val())// 添加或修改多个键err = rdb.MSet("age", "20", "gender", "男", "length", "190").Err()if err != nil {fmt.Printf("mset err,err:%v\n", err)return}// 删除一个键err = rdb.Del("gender").Err()if err != nil {fmt.Printf("del err,err:%v\n", err)return}// 获取一个键name, err := rdb.Get("name").Result()if err != nil {if err == redis.Nil {fmt.Printf("this key not found, err:%v\n", err)} else {fmt.Printf("get error,err:%v\n", err)return}}fmt.Println("name:", name)// 获取多个键mulkey, err := rdb.MGet("name", "age").Result()if err != nil {if err == redis.Nil {fmt.Printf("this key not found, err:%v\n", err)} else {fmt.Printf("get error,err:%v\n", err)return}}fmt.Println(mulkey)// 判断键是否存在fmt.Println(rdb.Exists("gender"))// 查看键类型fmt.Println(rdb.Type("name"))// 设置键的过期时间rdb.Expire("length", time.Second*20) // 第二个时间参数是以纳秒为单位,所以直接用了time.Second// 查看键的过期时间fmt.Println(rdb.TTL("name"))// 创建有过期时间的键值对rdb.Set("gender", "男", time.Second*20)// 获取原值并设置新值fmt.Println(rdb.GetSet("name", "rzxy"))// 给值后追加内容rdb.Append("name", "is rzzy")// 获取值的长度fmt.Println(rdb.StrLen("name"))// 只有当键值对不存在时才能设置键值对rdb.SetNX("location", "China", 0)// 给纯数字键值对的值自增1fmt.Println(rdb.Incr("age"))// 给纯数字键值对的值自减1fmt.Println(rdb.Decr("age"))// 给纯数字键值对的值自增nfmt.Println(rdb.IncrBy("age", 100))// 给纯数字键值对的值自减nfmt.Println(rdb.DecrBy("age", 100))// 获取值的0~3长度内的内容fmt.Println(rdb.GetRange("name", 0, 3))// 从开始位置开始覆写值rdb.SetRange("name", 9, "eihei")// 展示下现在所有的键值对for _, s := range rdb.Keys("*").Val() {fmt.Println(s, ":", rdb.Get(s).Val())}
}// List示例
func listEx() {// 从列表左边插入一个或多个值rdb.LPush("userName", "rzzy", "rzxy")// 从列表右边插入一个或多个值rdb.RPush("nickName", "SukiMegumi", "dtmyx")// 从列表左边弹出一个值,右边的话把L改成Rfmt.Println(rdb.LPop("userName"))// 从第一个列表的右边弹出一个值,将这个弹出的值添加到第二个列表的左边rdb.RPopLPush("userName", "nickName")// 按照索引下标获取元素rdb.LIndex("nickName", 0)// 获取列表长度rdb.LLen("nickName")// 插入查找到的第一个Value后(插入其之前的话,把After改成Before)rdb.LInsertAfter("userName", "rzzy", "eihei")// 删除 1 个value值rdb.LRem("userName", 1, "eihei")// 将列表key下标为index的值替换为valuerdb.LSet("useName", 0, "rzxy")}// set示例
func setEx() {// 添加一个或多个元素到集合key中,已存在的忽略掉rdb.SAdd("name", "rzzy", "rzxy", "dtmyx", "SukiMegumi", "eihei")rdb.SAdd("nickName", "a", "rzxy", "b", "v", "eihei")// 取出该集合所有元素fmt.Println(rdb.SMembers("name"))// 判断集合中是否含有某个元素fmt.Println(rdb.SIsMember("name", "rzzy"))// 返回该集合元素个数fmt.Println(rdb.SCard("name"))// 删除集合中的某个值fmt.Println(rdb.SRem("name", "rzxy"))// 随机从集合中弹出一个值fmt.Println(rdb.SPop("name"))// 随机从集合中弹出n个值fmt.Println(rdb.SPopN("name", 1))// 把集合中的一个值从一个集合移动到另一个集合fmt.Println(rdb.SMove("name", "nickName", "SukiMegumi"))// 返回两个集合的交集元素,并集为SUnion,差集为SDifffmt.Println(rdb.SInter("name", "nickName"))}// zset示例
func zsetEx() {languages := []redis.Z{{Score: 64.96, Member: "JavaScript"},{Score: 56.07, Member: "HTML/CSS"},{Score: 48.24, Member: "Python"},{Score: 47.08, Member: "SQL"},{Score: 35.35, Member: "Java"},}// 将一个或多个member及其score添加到有序集合中rdb.ZAdd("programRank", languages...)// 返回有序集中,下标在start和stop之间的元素fmt.Println(rdb.ZRange("programRank", 0, 3))// 返回有序集中,所有score介于min和max之间的成员,有序成员按从小到大排序(从大到小用rdb.ZRevRangeByScoreWithScores())fmt.Println(rdb.ZRangeByScoreWithScores("programRank", redis.ZRangeBy{Min: "50", Max: "100"}))// 让元素的score加上指定值fmt.Println(rdb.ZIncrBy("programRank", 3, "Java"))// 自减fmt.Println(rdb.ZIncrBy("programRank", -3, "Java"))// 删除该集合下指定的元素fmt.Println(rdb.ZRem("programRank", "Java"))// 统计该集合,min和max区间内元素个数fmt.Println(rdb.ZCount("programRank", "30", "60"))// 返回该值的在集合中的排名,排名从0开始(按score从小到大排序,倒序使用ZRevRank)fmt.Println(rdb.ZRank("programRank", "JavaScript"))
}// hash 示例
func hashEx() {// 给哈希表中filed赋值valuerdb.HSet("user10001", "name", "rzzy")// 批量设置filed值user10001 := map[string]interface{}{"name": "rzzy","age": "100","height": "180",}rdb.HMSet("user10001", user10001)// 设置哈希表中的filed的值,当且仅当该field不存在rdb.HSetNX("user10001", "weight", "80")// 从哈希表中去除filed的值fmt.Println(rdb.HGet("user10001", "age"))// 判断哈希表中,给定filed是否存在fmt.Println(rdb.HExists("user10001", "location"))// 列出该哈希表中所有的filedfmt.Println(rdb.HKeys("user10001"))// 列出该哈希表中所有的valuefmt.Println(rdb.HVals("user10001"))// 列出该哈希表所有内容fmt.Println(rdb.HGetAll("user10001"))// 为哈希表field的纯数字值加上增量(负数也行)fmt.Println(rdb.HIncrBy("user10001", "age", -1))
}func main() {if err := initClient(); err != nil {fmt.Printf("init redis client failed, err:%v\n", err)return}fmt.Println("connect redis success...")// 释放相关资源defer rdb.Close()// 字符串以及一些键值对的基本操作fmt.Println("************************* sting类型 **********************************")stringEx()rdb.FlushDB() // 清空当前库// list示例fmt.Println("************************* list类型 **********************************")listEx()rdb.FlushDB() // 清空当前库// set 示例fmt.Println("************************* set类型 **********************************")setEx()rdb.FlushDB() // 清空当前库// zset 示例fmt.Println("************************* zset类型 **********************************")zsetEx()rdb.FlushDB() // 清空当前库// hash 示例fmt.Println("************************* hash类型 **********************************")hashEx()rdb.FlushDB() // 清空当前库
}
redis学习 + go-redis 基本使用相关推荐
- Redis学习笔记~Redis在windows环境下的安装
Redis是一个key-value的存储系统,它最大的特点就是可以将数据序列化到文件中. redis存储在服务器的内存或者文件中,它不是session,不是cookies,它只是个更安全,更稳定,更可 ...
- Redis学习笔记---Redis的主从复制
Redis学习笔记-Redis的主从复制 1.Redis的高可用性 高可用性(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性. Rei ...
- Redis学习笔记---Redis的模式订阅与退订
Redis学习笔记-Redis的模式订阅与退订 1.发布订阅简介 发布订阅是一种通信的模式,Redis提供了发布订阅功能,可以用于消息的传输 Redis的发布订阅机制包括三个部分,publisher( ...
- Redis学习笔记---Redis的事务
Redis学习笔记-Redis的事务 1. Redis事务(弱事务)和Mysql事务对比 Atomicity(原子性):构成事务的的所有操作必须是一个逻辑单元,要么全部执行,要么全部不执行. Redi ...
- 【Redis学习】Redis管理命令总结
1.键管理 之前通过对五种数据类型的操作命令的学习发现,Redis在对每种数据进行处理之前,都要先指定该数据的key,然后再指定对该数据进行何种操作. Redis中的key有点类似于Java中的变量名 ...
- 【Redis学习】Redis的安装、管理、适用场合以及使用
1.Redis概述 我们知道,内存是电脑主板上的存储部件,用于存储当前正在使用的数据和程序,CPU可以与内存直接沟通,所以访问速速非常高:而外存数据必须加载到内存以后程序才能使用.如果把CPU当做一个 ...
- Redis学习之Redis概述及原理、基本操作及持久化
一.Redis介绍 Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 它通常被称为数据结构服务 ...
- Redis学习之Redis概述与安装以及性能测试
Redis入门 概述 Redis是什么 Redis(remote dictionary server)远程字典服务器 是一个开源的使用c语言编写.支持网络.可基于内存亦可持久化的日志型.key-val ...
- redis学习(五) redis实现购物车
<redis实战> 第二章 每个用户的购物车都是一个散列,这个散列存储了商品ID与商品订购数量之间的映射 对商品数量的验证由web应用程序负责,我们要做的就是在商品订购的数量出现变化时,对 ...
- redis学习之——redis.conf配置(基本)文件学习
# Redis configuration file example# Note on units: when memory size is needed, it is possible to spe ...
最新文章
- mysql5.0镜像_Mysql5.0学习笔记(一)
- git push github SSL报错处理
- Python3基础教程:元类详解
- C++ 指针函数和函数指针
- 苏宁张近东:春节期间拿出3亿补贴一线员工
- matlab 2018 ccs,Matlab2018a 与ccs7生成tms320F2812代码调试记录
- JavaScript30秒, 从入门到放弃之Array(七)
- 如何删除计算机中的“天翼云盘”图标
- 华科计算机专业课考研考什么,华科计算机考研专业课有哪些
- Spire.Office for Java 7.5.4
- Char类的常用方法及说明
- php的作品简介怎么写,作品简介(参赛作品简介怎么写)
- 全国计算机比赛图片,我校学子获2020年“中国高校计算机大赛-网络技术挑战赛”全国总决赛一等奖(图)-全国文明校园建设网...
- Aruba protal 认证 图标
- WAITED TOO LONG FOR A ROW CACHE ENQUEUE LOCK
- 微信内域名被多人投诉导致无法访问怎么办?
- Android图片加载框架最全解析(八),带你全面了解Glide 4的用法
- 量子通信——量子的概念与量子力学
- 软件定义的网络(中)
- Transform.setIdentity()invert()transpose()
热门文章
- ABP+AdminLTE+Bootstrap Table权限管理系统第二节--在ABP的基础做数据库脚本处理
- 更换ubuntu软件源为阿里源,解决ubuntu下载安装软件慢的问题并安装open-vm-tools和open-vm-tools-desktop
- 好团队激活个人读后感
- 大屏的代价:iPhone 6 Plus换屏要花129美元
- php开发数独,php解数独 - AA星梦无痕AA的个人空间 - OSCHINA - 中文开源技术交流社区...
- Revit插件 | 精装模块15个新功能正式上线,快来体验
- java自制SQL假数据生成器
- 斯坦福密码学-3-分组密码block_cipher
- 匠心、携手、深耕:5G Capital展现出的无线产业新范式
- KUBEADM 搭建集群(2)