一、Redis入门
罪魁祸首——关系型数据库
性能瓶颈:磁盘IO性能低下(CPU数据交换是和高速缓存cache,cache的数据交换和谁做,和内存。内存的数据交换和谁做,和磁盘做,这些基础数据存在硬盘上,一层层往上传递。数据库是保存在磁盘上的)
扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
解决思路
降低磁盘IO次数,越低越好 ------内存存储 这样就出现NoSQL 内存型数据库
去除数据间关系,越简单越好 -------不存储关系,仅存储数据
Nosql
NoSQL:即 Not-Only SQL( 泛指非关系型的数据库),作为关系型数据库的补充。
作用:应对基于海量用户和海量数据前提下的数据处理问题。
特征:
可扩容,可伸缩
大数据量下高性能
灵活的数据模型
高可用
常见 Nosql 数据库:
Redis
memcache
HBase
MongoDB
解决方案(电商场景)
1. 商品基本信息 存到Mysql
名称
价格
厂商
2. 商品附加信息 存到MongoDB
描述
详情
评论
3. 图片信息 分布式文件系统
4. 搜索关键字 ES 存储,Lucene、solr
5. 热点信息
高频
波段性 存到 Redis、memcache、tair
Redis
概念:Redis (REmote DIctionary Server) 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库。
Redis特征:
1.数据间没有必然的关联关系
2.内部采用单线程机制进行工作
3.高性能。官方提供测试数据,50个并发执行100000 个请求,读的速度是110000 次/s,写的速度是81000次/s。
4.多数据类型支持
字符串类型 string
列表类型 list
散列类型 hash
集合类型 set
有序集合类型 sorted_set
4.持久化支持。可以进行数据灾难恢复
Redis的应用:
为热点数据加速查询(主要场景),如热点商品、热点新闻、热点资讯、推广类等高访问量信息等
任务队列,如秒杀、抢购、购票排队等
即时信息查询,如各位排行榜、各类网站访问统计、公交到站信息、在线人数信息(聊天室、网站)、设备信号等
时效性信息控制,如验证码控制、投票控制等
分布式数据共享,如分布式集群架构中的 session 分离
消息队列
分布式锁
Redis的下载与安装
windows安装的是3.2版本,因为最早redis是没想支持windows,下载地址https://github.com/MSOpenTech/redis/tags,找到3.2版本,下载zip格式的包。
核心文件:
redis-server.exe 服务器启动命令
redis-cli.exe 命令行客户端
redis.windows.conf redis核心配置文件
redis-benchmark.exe 性能测试工具
redis-check-aof.exe AOF文件修复工具
redis-check-dump.exe RDB文件检查工具(快照持久化文件)
安装完,点击redis-server.exe可能出现闪退,这时候可以新建一个redis.bat,里面写上redis-server.exe redis.windows.conf 这行,因为启动时候用到的是这两个文件。就可以启动了。
然后再点击redis-cli.exe启动它的客户端
Redis的基本操作
信息添加:
功能:设置key,value
设置 set key value
二、Redis数据类型
数据存储类型介绍,
string
hash
list
set
sorted_set
数据类型实践案例
业务数据的特殊性
作为缓存使用
1、原始业务功能设计
秒杀
2、运营平台监控的突发高频访问数据
突发时政要闻,被强势关注围观
3、高频、复杂的统计数据
在线人数
附加功能
系统功能优化或升级
单服务器升级集群
Session管理
Token管理
Redis数据类型(5中常用类型)
string 类比java的String
hash 类比java的HashMap
list 类比java的LinkedList
set 类比java的HashSet
sorted_set 类比java的TreeSet
String 类型数据的基本数据
但数据操作与多数据操作的选择
set 一次设置一个值 mset 一次设置多个值
String 类型数据的扩展操作
解决方案
设置数值数据增加指定范围的值
incr key
incrby key increment
incrbyfloat key increment
设置数值数据减少指定范围的值
decr key
decrby key increment
redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响。
设置数据具有指定的生命周期
setex key seconds value
psetex key milliseconds value
redis 控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作
string 类型数据操作的注意事项
数据操作不成功的反馈与数据正常操作之间的差异
string 类型数据操作的注意事项
①表示运行结果是否成功
(integer) 0 → false 失败
(integer) 1 → true 成功
②表示运行结果值
(integer) 3 → 3 3个
(integer) 1 → 1 1个
数据未获取到 (nil)等同于null
数据最大存储量 512MB
数值计算最大范围(java中的long的最大值) 9223372036854775807
redis 中key的设定格式,
数据库中的热点数据key命名惯例:
表名 :主键名 :主键值 :字段名
order :id :234324532 :name
news :id : 23325454 :title
hash类型
需要的存储结构:
一个存储空间保存多个键值对数据
hash类型:底层使用哈希表结构实现数据存储 存的是一个群组
hash 类型数据的基本操作
添加/修改数据
hset key field value 例 hset user name zhangsan hset user age 20
获取数据
hget key field
hgetall key
删除数据
hdel key field1 [field2]
添加修改多个数据
hmset key field1 value1 field2 value2 例 hmset user age 20 name zhangsan
获取多个数据
hmset key field1 field2 ...
获取哈希表中字段的数量
hlen key
获取哈希表中是否存在指定的字段
hexists key field
hash类型数据扩展操作
获取哈希表中所有的字段名或字段值
hkeys key
hvals key
设置指定字段的数值数据增加指定范围的值
hincrby key field increment
hincrbyfloat key field increment
hash 类型数据操作的注意事项
hash类型下的value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
每个 hash 可以存储 232 - 1 个键值对
hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用
hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈
hash类型应用场景
业务场景
电商网站购物车设计与实现
业务分析
仅分析购物车的redis存储模型
添加、浏览、更改数量、删除、清空
购物车于数据库间持久化同步(不讨论)
购物车于订单关系(不讨论)
提交购物车:读取数据生成订单
商家临时价格调整:隶属于订单级别
未登录用户购车信息存储(不讨论)
cookie存储
hash类型应用场景
解决方案
以客户id作为key,每位客户创建一个hash存储结构存储对应的购物车信息
将商品编号作为field,购买数量作为value进行存储
添加商品:追加全新的field和value
浏览:遍历hash
更改数量:自增/自减,设置value值
删除商品:删除field
清空:删除key
此处仅讨论购物车中的模型设计
购物车与数据库间持久化同步,购物车与订单间关系、未登录用户购物车信息存储不进行讨论。
list 类型
数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
list类型:保存多个数据,底层使用双向链表存储结构实现,哪边都能进,哪边都能出。
添加/修改数据
lpush key value1 [value2] …… 从左进入
rpush key value1 [value2] …… 从右进入
获取数据
lrange key start(索引) stop(索引) 从左查
lindex key index(索引)
llen key
例如:rpush list2 a b c
lrange list2 0 2
获取并移除数据
lpop key
例如:lpop list2
rpop key
list阻塞式,在这个时间内等,如果有就立刻取出来,如果没有就一直等,知道时间到了位置,取出空的
例如:blpop list2 10
blpop key1 [key2] timeout
brpop key1 [key2] timeout
brpoplpush source destination timeout
set类型
set类型:与hash存储结构完全相同,field作为value,value是nil
添加数据
sadd key member1 [member2]
获取全部数据
smembers key
删除数据
srem key member1 [member2]
获取集合数据总量
scard key
判断集合中是否包含指定数据
sismember key member
sorted_set
添加数据
zadd scores 94 zs
zadd scores 100 ls
获取全部数据
zrange scores 0 -1
zrevrange scores 0 -1
删除数据
zrem scores zs
按条件获取数据
zrangebysore key min max withscores
zrevrangebysore key max min withscores
条件删除数据
zremrangebyrank key start stop
zremrangebyscore key min max
三、Redis通用命令
key通用命令
key特征
key是一个字符串,通过key获取redis中保存的数据
key应该设计哪些操作?
1、对于key自身状态的相关操作,例如:删除、判定存在、获取类型等
例如:新建五种数据类型,set str str hset hash1 hash1 hash1 lpush list1 list1 sadd set1 set1 zadd zset1 1 zsete1
删除指定key
del key
获取key是否存在
exists key
获取key的类型
type key
2、对于key有效性控制相关操作,例如:有效期设定,判定是否有效,有效状态的切换等
为指定key设置有效期
expire key seconds 例如 expire str 3
pexpire key milliseconds
查看key的有效期
ttl key
pttl key
切换key从时效性转换为永久性
persist key
3、对于key快速查询操作,例如:按指定策略查询key
查询key
keys pattern 例如 keys *
* 匹配任意数量的任意符号
?配合一个任意符号
[] 匹配一个指定符号
4、key其他操作
为key改名
rename key newkey
renamex key newkey
对所有key排序
sort
其他key通用操作
help @generic
数据库通用指令
key重复问题
解决方案
redis为每个服务提供有16个数据库,编号从0到15
每个数据库之间的数据相互独立
切换数据库
select index
其他操作
quit
ping
echo message
db相关操作
数据移动
move key db
四、Jedis
Jedis简介
Jedis
SpringData Redis
HelloWorld(Jedis版),首先加入依赖坐标
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
public class JedisTest{
@Test
public void jedisTest(){
//1、连接redis
Jedis jedis = new Jedis("127.0.0.1","6379");
//2、操作redis
jedis.set("name","zhangsan");
String name =jedis.get("name");
System.out.println(name);
//3、关闭连接
jedis.close();
}
}
客户端连接redis的步骤
1、连接redis
2、操作redis
3、关闭redis。
Jedis读写redis数据
public class JedisTest{
@Test
public void testList(){
Jedis jedis = new Jedis("127.0.0.1","6379");
jedis.lpush("list1","a","b","c");
jedis.rpush("list1","a","b","c");
List<String> list1=jedis.lrange("list1",0,-1);
for(String s :list1){
System.out.println(s);
}
System.out.println(jedis.llen("list1"));
jedis.close();
}
@Test
public void testHash(){
Jedis jedis = new Jedis("127.0.0.1","6379");
jedis.hset("hash1","a1","b1");
jedis.hset("hash1","a2","b2");
jedis.hset("hash1","a3","b3");
Map<String ,String> hash1=jedis.hgetAll("hash1");
System.out.println(hash1);
System.out.println(jedis.hlen("hash1"));
jedis.close();
}
}
Jedis简易工具类开发
public class JedisUtils{
private static JedisPool jp=null;
private static String host =null;
private static int port;
private static int maxTotal;
private static int maxIdle;
static{
ResourceBundle rb = ResourceBundle.getBundle("redis");
host=rb.getString("redis.host");
port=Integer.parseInt(rb.getString("redis.port"));
maxTotal=Integer.parseInt(rb.getString("redis.maxTotal"));
maxIdle= Integer.parseInt(rb.getString("redis.maxIdle"));
JedisPoolConfig jpc=new JedisPoolConfig();
jpc.setmaxTotal(maxTotal);
jpc.setmaxIdle(maxIdle);
jp=new JedisPool(jpc,host,port);
}
public static Jedis getJedis(){
return jp.getResource();
}
}
可视化客户端
redis-desktop-manager 类似于mysql的navicat用法,界面的。