阿里云上redis外网无法访问的解决方案
- 启动命令
redis-server Rconfig/redis.conf
(在/usr/local/bin
目录下) - 原生客户端
redis-cli
数据类型
五种基本数据类型
- Redis-key
- String
- List
- Set
- Hash
- Zset
Redis-key
-
keys *
查看当前库所有key -
exists name
判断name
key 是否存在 -
move name 1
移除name -
expire name 10
设置name
10秒后过期 -
ttl name
检查过期时间 -
type name
查看当前key
的类型
String-字符串
-
keys *
获得所有key -
get name
获取name的value -
append name asd
在name加上值的末尾asd -
exists name
判断name是否存在
127.0.0.1:6379> keys * #获得所有key 1) "name" 2) "age" 127.0.0.1:6379> get name #获取值 "changan" 127.0.0.1:6379> append name love #添加字符串 (integer) 11 127.0.0.1:6379> get name "changanlove" 127.0.0.1:6379> exists name #判断它是否存在 (integer) 1
-
incr views
给 views 加1 -
decr views
给 views 减1 -
incrby views 10
给 views 加10(步长) -
decrby views 10
给 views 减10(步长) -
getrange
范围查询数据 -
setrange
修改(替换) -
setex key 60 "value"
设置短时数据
-
setnx key "redis"
仅在key不存在时生效,生成新的key-value(常用于分布式锁) -
mset 批量设置
-
mget 批量读取
-
msetnx
设置多个值 如果一个值设置失败,那么全部失败 (原子性)127.0.0.1:6379> msetnx k1 v1 k5 v5(integer) 0
-
getset
先获取在设置127.0.0.1:6379> set key value OK 127.0.0.1:6379> getset key hi --> 如果存在,返回当前的值,并设置新的值 "value" 127.0.0.1:6379> get key "hi" 127.0.0.1:6379> getset key1 hi --> 不存在返回nil则创建 (nil) 127.0.0.1:6379> get key1 "hi"
-
String的应用场景
- 计数器
- 统计多单位数量
- 粉丝数
- 对象缓存存储
List-列表
-
lpush
左存储rpush
右存储lrange
读取127.0.0.1:6379> lpush list 1 -->左存储 (integer) 1 127.0.0.1:6379> lpush list 2 (integer) 2 127.0.0.1:6379> lpush list 3 (integer) 3 127.0.0.1:6379> lrange list 0 -1 -->读取 1) "3" 2) "2" 3) "1" 127.0.0.1:6379> rpush list yyds -->右存储 (integer) 4 127.0.0.1:6379> lrange list -1 -1 -->读取 1) "yyds"
-
lpop
: 左移除(移除左边第一个)rpop
: 右移除(移除右边第一个)127.0.0.1:6379> lrange list 0 -1 1) "3" 2) "2" 3) "1" 4) "yyds" 127.0.0.1:6379> lpop list -->左移除 "3" 127.0.0.1:6379> rpop list -->右移除 "yyds" 127.0.0.1:6379> lrange list 0 -1 1) "2" 2) "1"
-
lindex
通过下标获取值127.0.0.1:6379> lrange list 0 -1 1) "zxc" 2) "asd" 3) "y" 4) "x" 5) "2" 127.0.0.1:6379> lindex list 0 "zxc" 127.0.0.1:6379> lindex list -1 "2"
-
llen
获取list的长度127.0.0.1:6379> llen list (integer) 5
-
lrem
删除 ‘精确匹配’127.0.0.1:6379> lrange list 0 -1 1) "1" 2) "1" 3) "1" 4) "1" 5) "zxc" 6) "asd" 7) "y" 8) "x" 9) "2" 127.0.0.1:6379> lrem list 2 1 (integer) 2 127.0.0.1:6379> lrange list 0 -1 1) "1" 2) "1" 3) "zxc" 4) "asd" 5) "y" 6) "x" 7) "2"
-
ltrim
截取127.0.0.1:6379> lrange list 0 -1 1) "hello" 2) "hello1" 3) "hello2" 4) "hello3" 5) "hello4" 6) "hello5" 127.0.0.1:6379> ltrim list 1 3 -->截取标号1-3之间的元素 OK 127.0.0.1:6379> lrange list 0 -1 1) "hello1" 2) "hello2" 3) "hello3"
-
rpoplpush
移除列表的最后一个元素,并移动到新的列表中127.0.0.1:6379> lrange list 0 -1 1) "hello1" 2) "hello2" 3) "hello3" 127.0.0.1:6379> RPOPLPUSH list mylist -->移除list的最后一个元素,并移动到新的mylist中 "hello3" 127.0.0.1:6379> lrange mylist 0 -1 1) "hello3"
-
lset
将列表中指定下标的值替换为另外一个(update)127.0.0.1:6379> lrange list 0 -1 1) "hello1" 2) "hello2" 127.0.0.1:6379> lset list 0 hi OK 127.0.0.1:6379> lrange list 0 -1 1) "hi" 2) "hello2"
-
linsert
将某一个具体的值插入列表某个元素的前后127.0.0.1:6379> lrange list 0 -1 1) "hi" 2) "hello2" 127.0.0.1:6379> linsert list After hello2 good -->在hello2之后插入 (integer) 3 127.0.0.1:6379> lrange list 0 -1 1) "hi" 2) "hello2" 3) "good" 127.0.0.1:6379> linsert list before hello2 good -->在hello2之前插入 (integer) 4 127.0.0.1:6379> lrange list 0 -1 1) "hi" 2) "good" 3) "hello2" 4) "good"
-
小结
-
list实际是一个链表,before , after,left ,right 都可以插入值
-
如果key 不存在,创建新的链表
-
如果key 存在,新增内容
-
如果移除了所有的值——空链表,也代表不存在
-
在两边插入或改动值,效率最高!中间元素,相对来说效率会低一点
可以用来做! 消息队列(Lpush Rpop) 左进右出 ,栈(Lpush Lpop)左进左出
-
Set
-
ssad
给集合添加值smembers
查看当前集合元素sismember
查看集合是否含有某元素, 有的话返回1 没有就是0scard
获取当前集合的个数screm
移除集合中某个元素127.0.0.1:6379> sadd mylist 1 -->给集合添加值 (integer) 1 127.0.0.1:6379> sadd mylist 2 -->给集合添加值 (integer) 1 127.0.0.1:6379> sadd mylist zxc -->给集合添加值 (integer) 1 127.0.0.1:6379> sadd mylist asd -->给集合添加值 (integer) 1 127.0.0.1:6379> SMEMBERS mylist -->查看当前集合元素 1) "zxc" 2) "asd" 3) "2" 4) "1" 127.0.0.1:6379> SISMEMBER mylist 1 -->判断1是否在集合mylist中 (integer) 1 127.0.0.1:6379> SISMEMBER mylist 3 -->判断3是否在集合mylist中 (integer) 0z 127.0.0.1:6379> scard mylist -->获取集合中元素个数 (integer) 4 127.0.0.1:6379> SREM mylist 2 (integer) 1 127.0.0.1:6379> SMEMBERS mylist -->查看当前集合元素 1) "zxc" 2) "asd" 3) "2" 4) "1" 127.0.0.1:6379> SMEMBERS mylist -->移除mylist中的元素"2" 1) "zxc" 2) "asd" 3) "1"
-
SRANDMEMBER
随机从集合中筛选一个数据127.0.0.1:6379> SRANDMEMBER mylist -->随机抽取 "asd" 127.0.0.1:6379> SRANDMEMBER mylist -->随机抽取 "asd" 127.0.0.1:6379> SRANDMEMBER mylist -->随机抽取 "2" 127.0.0.1:6379> SRANDMEMBER mylist -->随机抽取 "zxc" 127.0.0.1:6379> SRANDMEMBER mylist -->随机抽取 "1" 127.0.0.1:6379> SRANDMEMBER mylist -->随机抽取 "2"
-
spop
随机删除一个元素127.0.0.1:6379> SMEMBERS mylist 1) "zxc" 2) "asd" 3) "1" 127.0.0.1:6379> SPOP mylist -->随机删除 "zxc" 127.0.0.1:6379> SPOP mylist -->随机删除 "1" 127.0.0.1:6379> SPOP mylist -->随机删除 "asd"
-
smove
将一个指定的值移动到另外一个set集合中127.0.0.1:6379> smove myset yourset hello1 -->将 "hello1"从myset移动到yourset中 (integer) 1 127.0.0.1:6379> SMEMBERS myset 1) "hello2" 2) "hello5" 3) "hello" 4) "hello4" 5) "hello6" 6) "hello3" 127.0.0.1:6379> smembers yourset 1) "hello1"
-
SDIFF
查看2个集合的差集SINTER
查看2个集合的交集SUNION
查看2个集合的并集127.0.0.1:6379> smembers set1 1) "1" 2) "2" 3) "3" 4) "4" 127.0.0.1:6379> smembers set2 1) "3" 2) "4" 3) "5" 4) "6" 127.0.0.1:6379> sdiff set1 set2 -->差集 set1-set2 1) "1" 2) "2" 127.0.0.1:6379> sdiff set2 set1 -->差集 set2-set1 1) "5" 2) "6" 127.0.0.1:6379> SINTER set1 set2 -->交集 1) "3" 2) "4" 127.0.0.1:6379> Sunion set1 set2 -->并集 1) "1" 2) "2" 3) "3" 4) "4" 5) "5" 6) "6"
-
应用场景
微博等社交平台,A用户将所有的关注的人放在一个set集合中,将他的粉丝也放在一个集合中,从而实现!
Hash
-
hset
设置值hget
获取值hmset
批量设置值hmget
批量获取指定值hgetall
获取指定hashmap的值127.0.0.1:6379> hset myhash name zane -->set一个具体的 key-value (integer) 1 127.0.0.1:6379> hget myhash name -->get一个具体的 key-gvalue "zane" 127.0.0.1:6379> hmset myhash age 20 sex male OK 127.0.0.1:6379> hmget myhash age sex 1) "20" 2) "male" 127.0.0.1:6379> hgetall myhash -->获取键值对 1) "name" 2) "zane" 3) "age" 4) "20" 5) "sex" 6) "male"
-
hdel
删除指定的kv127.0.0.1:6379> hdel myhash age (integer) 1 127.0.0.1:6379> hget myhash age (nil)
-
hlen
查询集合有几组kvHEXISTS
查看集合的k是否存在hkeys
查看所有的keyhvals
查看所有的value127.0.0.1:6379> hlen myhash (integer) 2 127.0.0.1:6379> HEXISTS myhash age (integer) 0 127.0.0.1:6379> HEXISTS myhash sex (integer) 1 127.0.0.1:6379> hkeys myhash 1) "name" 2) "sex" 127.0.0.1:6379> hvals myhash 1) "zane" 2) "male"
-
HINCRBY
指定增量hsetnx
创建一个集合 如果这个集合没有数据 就放入数据 返回1 如果有数据 那么返回0原理同String、
-
应用场景
hash 用来处理变更的数据 user name age ,尤其是用户信息之类,经常变动的信息! hash 更适合与对象的存储,String 适合字符串的存储!
Zset(有序集合)
-
zadd
增加zrangebyscore
排序zrange
选择范围输出ZREVRANGE
逆序范围输出zrem
删除元素zcard
获取集合中元素数127.0.0.1:6379> zadd grades 88 ming -->添加元素 (integer) 1 127.0.0.1:6379> zadd grades 78 jack (integer) 1 127.0.0.1:6379> zadd grades 99 tom (integer) 1 127.0.0.1:6379> zadd grades 66 paul (integer) 1 127.0.0.1:6379> ZRANGEBYSCORE grades -inf inf -->从小到大排序 1) "paul" 2) "jack" 3) "ming" 4) "tom" 127.0.0.1:6379> ZRANGEBYSCORE grades -inf inf withscores -->从小到大排序并带者分数输出 1) "paul" 2) "66" 3) "jack" 4) "78" 5) "ming" 6) "88" 7) "tom" 8) "99" 127.0.0.1:6379> zrange grades 0 -1 -->选择范围输出 1) "paul" 2) "jack" 3) "ming" 4) "tom" 127.0.0.1:6379> ZREM grades jack -->删除元素 (integer) 1 127.0.0.1:6379> zrange grades 0 -1 1) "paul" 2) "ming" 3) "tom" 127.0.0.1:6379> ZREVRANGE grades 0 -1 -->逆序范围输出 1) "tom" 2) "ming" 3) "paul" 127.0.0.1:6379> zcard grades (integer) 3
-
应用场景
班级成绩排序,工资排序
消息优先级 带权重进行判断
排行榜应用实现 取 Top N测试
三种特殊数据类型
geospatial 地理位置
-
GEOADD
添加地理位置信息127.0.0.1:6379> GEOADD china:city 116.352963 40.409079 beijing (integer) 1 127.0.0.1:6379> GEOADD china:city 116.413384 39.910925 shanghai (integer) 1 127.0.0.1:6379> GEOADD china:city 104.072747 30.578994 chengdu (integer) 1 #格式 geoadd 纬度 经度 名称
-
GEODIST 展现两点之间的距离
127.0.0.1:6379> geodist china:city chengdu shanghai "1524928.5252" 127.0.0.1:6379> geodist china:city chengdu shanghai km "1524.9285" 127.0.0.1:6379> geodist china:city chengdu shanghai ft "5003046.3424" 127.0.0.1:6379> geodist china:city chengdu shanghai mi "947.5490"
单位(默认单位是米)
- m米
- km千米
- mi英里
- ft英尺
-
GEOPOS
获取地理位置信息127.0.0.1:6379> geopos china:city chengdu shanghai 1) 1) "104.07274872064590454" 2) "30.57899393079901529" 2) 1) "116.41338318586349487" 2) "39.9109247398676743"
-
GEORADIUS
以给定的经纬度为中心。找出某一半径内所有元素127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km -->找出该点方圆1000km内的点 1) "chengdu" 127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist -->withdist附带显示距离 1) 1) "chengdu" 2) "572.8305" 127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord -->withcoord附带显示经纬度 1) 1) "chengdu" 2) 1) "104.07274872064590454" 2) "30.57899393079901529"
-
GEORADIUSBYMEMBER
找出指定元素附近一定距离的元素127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km 1) "shanghai" 2) "beijing"
-
GEOHASH
将二维的经纬度转化为一维的字符串,如果两个字符串越接近,则代表距离越近127.0.0.1:6379> geohash china:city beijing chengdu 1) "wx4tzsjxuw0" 2) "wm6jbnxrwc0"
-
查看与删除
127.0.0.1:6379> zrange china:city 0 -1 #查看 1) "chengdu" 2) "shanghai" 3) "beijing" 127.0.0.1:6379> zrem china:city beijing #删除 (integer) 1 127.0.0.1:6379> zrange china:city 0 -1 #查看 1) "chengdu" 2) "shanghai"
Hyperloglog
优点:占用内存小,2^64不同的元素技术,只需要12kb内存
-
pfadd
:添加数据pfcount
:查询数据pfmerge
:合并数据127.0.0.1:6379> PFADD mykey 1 2 3 4 56 6 8 9 8 7 a s d f g h h #添加数据 (integer) 1 127.0.0.1:6379> pfcount mykey #查询数据 (integer) 15 127.0.0.1:6379> PFADD mykey2 z x c v b n m#添加数据 (integer) 1 127.0.0.1:6379> pfmerge mykey0 mykey2 mykey#合并数据 (pfmerge 目标集合 源集合……) OK 127.0.0.1:6379> pfcount mykey0#查询数据 (integer) 22
Bitmaps(位图) 位存储
只要是2位数的数据结构就可以用,只有 0和1 两个状态
如:登录/未登录 活跃/不活跃 打卡/未打卡
-
setbit
设值 setbit key offset valuegetbit
取值 getbit key offsetbitcount
查询 bitcount key [start end]127.0.0.1:6379> setbit sign 0 0 (integer) 1 127.0.0.1:6379> setbit sign 1 1 (integer) 0 127.0.0.1:6379> setbit sign 2 1 (integer) 0 127.0.0.1:6379> getbit sign 1 (integer) 1 127.0.0.1:6379> bitcount sign #统计打卡天数(value为1的元素数量) (integer) 2
事务
所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!
Redis的事务流程:
-
开启事务 (multi)
-
命令入队 ( )
-
执行事务 (exec)/取消事务(discard)
正常执行事务
127.0.0.1:6379> multi #开启事务 OK #命令入队 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> set k3 v3 QUEUED 127.0.0.1:6379(TX)> get k2 QUEUED 127.0.0.1:6379(TX)> del k3 QUEUED 127.0.0.1:6379(TX)> exec #执行事务 1) OK 2) OK 3) OK 4) "v2" 5) (integer) 1 127.0.0.1:6379> MULTI OK 127.0.0.1:6379(TX)> DISCARD #取消事务 OK
编译型异常,实务中所有命令都不会被执行
127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> setget k3 v3 (error) ERR unknown command `setget`, with args beginning with: `k3`, `v3`, 127.0.0.1:6379(TX)> set k4 v4 QUEUED 127.0.0.1:6379(TX)> EXEC (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k4 (nil)
运行时异常,错误的命令抛出异常,正确的命令正常执行
127.0.0.1:6379> set k1 "v1" OK 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> incr k1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> set k3 v3 QUEUED 127.0.0.1:6379(TX)> EXEC 1) (error) ERR value is not an integer or out of range 2) OK 3) OK 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> get k3 "v3"
监控 Watch
悲观锁
- 认为什么时候都会出问题,无论进行什么事务都会加锁。
乐观锁
- 认为什么时候都不会出问题,不上锁,更新数据时判断一下期间是否有人改动过数据
- 获取version
- 更新时比较version
Redis 监视测试
正常执行成功
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> WATCH money #监视money对象
OK
127.0.0.1:6379> multi #事务正常结束,数据期间未发生变动,此时正常执行成功!
OK
127.0.0.1:6379(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> EXEC
1) (integer) 80
2) (integer) 20
线程1
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 1555
OK
线程2
127.0.0.1:6379> WATCH money #监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED
127.0.0.1:6379(TX)> exec #执行前,另一个线程修改了money的值,此时会导致事务执行失败
(nil)
127.0.0.1:6379> get money
"1555"
解决办法:
127.0.0.1:6379> unwatch #解锁
OK
127.0.0.1:6379> watch money #再次监视,获取最新的version
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 1
QUEUED
127.0.0.1:6379(TX)> incrby money 1
QUEUED
127.0.0.1:6379(TX)> EXEC #比对监视的值是否发生变化
1) (integer) 1454
2) (integer) 1455
Jedis
1.导入依赖
<dependencies>
<!--导入jedis的包-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
<!--导入fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
</dependencies>
2.编码测试
-
连接数据库
package com.zane; import redis.clients.jedis.Jedis; public class TestPing { public static void main(String[] args) { //1.new jedis对象 Jedis jedis = new Jedis("47.101.133.12",6379); //jedis所有命令均为我们之前学习的所有指令 System.out.println(jedis.ping()); } }
控制台输出"pong",代表连接成功。
-
操作命令
……
package com.zane; import com.alibaba.fastjson.JSONObject; import redis.clients.jedis.Jedis; import redis.clients.jedis.Transaction; public class TestMulti { public static void main(String[] args) { //1.new jedis对象 Jedis jedis = new Jedis("47.101.133.12",6379); JSONObject jsonObject = new JSONObject(); jsonObject.put("hello","world"); jsonObject.put("name","jack"); //开启事务 Transaction multi = jedis.multi(); String string = jsonObject.toJSONString(); try {