一、Redis基础入门
1. Redis存在的意义
各种网站崩了的现象,由于海量用户,高并发 导致。
其中罪魁祸首就是关系型数据库:
- 性能瓶颈:磁盘IO性能低下
- 扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
用Redis来解决问题的思路:
- 用内存存储(降低磁盘IO次数,越低越好)
- 不存储关系,只存储数据(去除数据间关系,越简单越好)
2. Nosql
-
Nosql(Not-Only SQL):作为关系型数据库的补充。用内存存储;不存储关系,只存数据
-
Nosql特征:
- 可扩容 可伸缩
- 大数据量下的高性能
- 灵活的数据模型
- 高可用
-
常见的Nosql数据库:Redis、memcache、HBase、MongoDB
3. Redis特征
-
数据间没有必然的关联关系,都是一个个key-value
-
内部采用单线程机制进行工作
redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响。
-
高性能。
-
多数据类型支持
- 字符串类型 string
- 列表类型 list
- 散列类型 hash
- 集合类型 set
- 有序集合类型 sorted_set
-
持久化支持。(可以进行数据灾难恢复)
4. Redis的应用
- 为热点数据加速查询(Redis的主要场景),如热点商品、热点新闻、等高访问量信息
- 任务队列,如秒杀、抢购、购票排队等
- 即时信息查询,如排行榜、公交到站信息、网站在线人数等
- 时效性信息控制,如验证码、投票等
- 分布式数据共享,如分布式集群架构中的session分离
- 消息队列
- 分布式锁
5. Redis数据存储格式
- redis自身是一个Map,其中所有的数据都是采用key:value的形式存储
- 其中key永远是string类型,redis中说数据类型都指的是value的数据类型
6. Redis中key的命名规范
-
key的命名规范:(表名: 主键名: 主键值: 字段名)。eg:
set user:id:123:fansNum 200
-
在redis中以json格式存value值用户信息
set user:id:123 {id:123, blog:879, fans: 200}
7. Redis的可视化客户端桌面工具
Redis Desktop Manager
Redis几种类型的可视化工具(桌面版、web版、ide的插件版等)
二、Redis的下载安装
1. Windows版
windows版主要是初学者不了解linux的人用于学习redis用的,真正要用redis还是要跑在Linux上
下载地址,下载完解压即可
2. Linux版
1) 安装步骤
-
下载(这里下的是4.0.0的版本)
wget http://download.redis.io/releases/redis-4.0.0.tar.gz
-
解压
tar –xvf redis-4.0.0.tar.gz
-
编译 + 安装 (这一步要把目录切换到 cd redis-4.0.0/src 文件目录下)
make install //若安装不成功,用命令(可能是用户权限不够?) sudo apt install redis-server
到此已安装完成,可以启动server和cli测试一下
-
启动server和cli,然后set get测试一下
//1.在redis-4.0.0/src目录下启动服务端 redis-server //2.启动客户端 redis-cli
2)启动redis服务的不同方式
-
指定端口启动redis服务
(当要多个redis服务时,在启服务的时候就指定端口,通过指定不同的端口指定不同的redis服务)
redis-server --port 6380
redis客户端连接时也指定端口
redis-cli -p 6380
-
通过配置文件启动redis服务(实现启动多台redis服务)
-
先在redis目录下设置配置文件(类似原有的redis-4.0.0/redis.conf),可以对应每个服务有一个配置文件
-
然后启动redis服务时指定配置文件
//1.切换到redis服务下 cd redis-4.0.0 //2.创建一个文件夹conf,就用来存放redis各个服务的配置文件 mkdir conf //3.在redis-4.0.0/conf目录下,新建配置文件redis-6379.conf vim redis-6379.conf //打开redis-6379.conf后写一些配置 port 6379 daemonize yes logfile "6379.log" dir /redis-4.0.0/data //4.以配置文件形式启动redis服务 redis-server conf/redis-6379.conf //启动几个redis服务设置几个配置文件,然后几个redis服务就可以在同一个机器上跑
redis配置文件中的一些配置内容
- daemonize yes :以守护进程方式启动,使用本启动方式,redis将以服务的形式存在,日志将不再打印到命令窗口中
- port 6***: 设定当前服务启动端口号
- logfile "6***.log“ :设定日志文件名,便于查阅
- dir “/自定义目录/redis/data“ :设定当前服务文件保存位置,包含日志文件、持久化文件等
-
三、 Redis数据类型
1. string类型
-
string类型,一个存储空间保存一个数据,最简单的数据类型,通常使用字符串,若字符串以整数的形式展示,可以作为数字操作使用,但他还是字符串
-
string的基本操作
Redis客户端cmd操作:
set key value //设置(原有的覆盖,没有的追加) get key //获取 del key //删除 mset key1 value1 key2 value2… //添加修改多个数据 multiple mget key1 key2… //获取多个数据 strlen key //获取数据字符个数(字符串长度) append key value //追加到原始信息后部(若原始信息存在就追加,否则新建)
-
string的单数据操作和多数据操作怎么选择(set 和 mset)
一条指令的执行时间 = 指令发送给redis的时间 + redis执行指令的时间 + redis返回执行结果的时间
根据消耗的时长,选择set还是mset
-
-
string的扩展操作
-
设置数值增加或减少指定范围的值
//设置数值增加或减少指定范围的值 incr key //+1 decr key //-1 incrby key increment //+increment decrby key increment //-increment incrbyfloat key increment //注意,若原始数据不能转为数值或超越了redis数值上线范围,将报错 //这个方案:可以用redis来控制数据库表主键id,为数据库表主键提供生成策略,保证主键唯一性
-
设置数据具有指定的生命周期
setex key seconds value psetex key millisecends value
2. hash类型
-
hash类型,一个存储空间保存多个键值对数据,底层使用哈希表结构实现数据存储。适用场景:适用存一个表中的多个字段的值,把各个字段搞在一个里面,又要方便获取修改
hash类型,指key-value中的value是hash类型的,即value又是一个key-value类型。
即结构是key-{fields-values}。 key-hash{field1-value1; field2-value2;field3-value3…}
-
注意:hash类型下的value只能存字符串,不允许存其它类型的数据
-
应用场景eg:电商网站购物车:用户id做key,商品id做field,数量做value
-
-
hash的基本操作 (在redis客户端的cmd指令)
//1.添加修改数据 hset key field value //2.获取数据 hget key field hgetall key //3.删除数据 hdel key field1 [field2] //4.添加修改多个数据 hmset key field1 value1 field2 value2 … //5.获取多个数据 hmset key field1 field2 … //6.获取哈希表中字段的数量 hlen key //7.获取哈希表中是否存在指定的字段 hexists key field
-
hash数据的扩展操作
//8.获取哈希表中所有的字段名(field)或字段值(value) hkeys key hvals key //9.设置指定字段的数值数据 增加指定范围的值 hincrby key field increment hincrbyfloat key field increment
3. list类型
-
list类型 [ key - list ]
-
数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
-
需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
-
list类型:保存多个数据,底层使用双向链表存储结构实现
-
应用场景举例:(朋友圈的点赞列表存储)
朋友圈是key,点赞列表是:list类型的value,点赞操作是:rpush,取消点赞lrem
redis 应用于具有操作先后顺序的数据控制
-
-
list类型的操作
//1.添加/修改数据 lpush key value1 [value2] …… //从左边进数据 rpush key value1 [value2] …… //右边进 //2.获取数据 lrange key start stop //取一个范围内的多个数据 (注意有顺序的概念) //当不知道list总共有多少个数据时,可以用 lrange list1 0 -1 (-1表示倒数第一个) lindex key index llen key //list长度 //3.获取并移除元素 lpop key rpop key //4.规定时间内获取并移除数据 (b代表block阻塞) blpop key1 [key2] timeout brpop key1 [key2] timeout brpoplpush source destination timeout //阻塞的获取数据理解:现在的list中没有这个数据,不代表以后这个list中没有这个数据。 //blpop表示可以等timeout时间范围内只要有这个数据就获取并移除。 //key1 [key2] 表示可以从多个list中等待找这个数据 (理解像多个任务队列中取任务一样) //5.移除指定数据 lrem key count value //count表示移除几个相同的元素
-
list的注意事项
- list中保存的数据都是string类型的
- list具有索引的概念,操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
- 获取全部数据操作结束索引设置为-1
- list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加载
4. set类型
-
set类型
-
存储大量的数据,在查询方面提供更高的效率(比起list存储效率高,因为list底层是链表,不利于查询)
-
set类型底层结构:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
理解底层结构,set整个是key - hash,其中hash的key-value中的key存真正的数据,value不存东西
Java中的HashSet 的内部实现使用的是HashMap,只不过所有的value都指向同一个对象
Redis的Set结构也是一样,它的内部也是用hash结构,所有的value都指向同一个内部值
其实就是不允许重复的集合
-
-
set类型的基本操作
//1.添加数据 sadd key member1 [member2] //2.获取全部数据 smembers key //3.删除数据 srem key member1 [member2] //4.获取集合数据总量 (该set集合中有几个数据) scard key //5.判断集合中是否包含指定数据 sismember key member
-
set类型的扩展操作
//6.随机获取集合中指定数量的数据 (原集合数据不变) srandmember key [count] //7.随机获取集合中的某个数据并将该数据移出集合 (原集合数据改变) spop key [count] //8.求两个集合的交、并、差集 sinter key1 [key2] sunion key1 [key2] sdiff key1 [key2] //9.求两个集合的交、并、差集并存储到指定集合中 sinterstore destination key1 [key2] sunionstore destination key1 [key2] sdiffstore destination key1 [key2] //10.将指定数据从原始集合中移动到目标集合中 smove source destination member
-
set的注意事项
- set 类型不允许数据重复,若添加的数据在 set 中已经存在,将只保留一份(添加已存在的数据时失败)
- set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
5. sorted_set类型
-
sorted_set类型
-
数据排序有利于数据的有效展示,需要提供一种可以根据自身特征进行排序的方式
-
sorted_set类型:在set的存储结构基础上添加可排序字段
底层数据类型:key - hash( value - nil - score),会根据score大小进行排序
sorted_set 底层存储还是基于set结构的,因此数据不能重复,如果重复添加相同的数据,score值将被反复覆盖,保留最后一次修改的结果
-
-
sorted_set基本操作
//1.添加数据 zadd key score1 member1 [score2 member2] //2.获取全部数据 zrange key start stop [WITHSCORES] zrevrange key start stop [WITHSCORES] //不加withscores会展示排好序的数据,加withscores展示排好序的数据和分数 //zrange是正向从小到大的顺序,zrevrange是从大到小 //3.删除数据 zrem key member [member ...] //4.按条件获取数据 zrangebyscore key min max [WITHSCORES] [LIMIT] zrevrangebyscore key max min [WITHSCORES] //5.条件删除数据 zremrangebyrank key start stop zremrangebyscore key min max //min与max用于限定搜索查询的条件 //start与stop用于限定查询范围,作用于索引,表示开始和结束索引 //6.获取集合数据总量 zcard key zcount key min max //7.集合交、并操作 zinterstore destination numkeys key [key ...] zunionstore destination numkeys key [key ...] //8.获取数据对应的索引(排名) zrank key member zrevrank key member //9.score值获取与修改 zscore key member zincrby key increment member
四、Redis的通用指令
1. key的通用指令
//1.删除指定key
del key
//2.获取key是否存在
exists key
//3.获取key的类型
type key
//4.为指定key设置有效期
expire key seconds
pexpire key milliseconds //pexpire和expire区别是时间单位不同
expireat key timestamp //3和4指令使用时间戳,linux系统中用的
pexpireat key milliseconds-timestamp
//5.获取key的有效时间
ttl key
pttl key
//6.切换key从时效性转换为永久性
persist key
//7.查询key
keys pattern
/**
pattern 写查询模式规则
* 匹配任意数量的任意符号
?配合一个任意符号
[] 匹配一个指定符号
举例:
keys * 查询所有
keys it* 查询所有以it开头
keys *heima 查询所有以heima结尾
keys ??heima 查询所有前面两个字符任意,后面以heima结尾
keys user:? 查询所有以user:开头,最后一个字符任意
keys u[st]er:1 查询所有以u开头,以er:1结尾,中间包含一个字母,s或t
*/
//8.为key改名
rename key newkey //redis中若已有新名字则会覆盖
renamenx key newkey //若新名字不存在的时候改成功,若redis里已有新名字则不成功
//9.对所有key排序
sort
//10.其他key的通用操作
help @generic
2. redis数据库的通用操作
-
Redis数据库
-
Redis为每个服务提供有16个数据库,编号index从0到15,每个数据库之间的数据相互独立
(感觉类似mysql中的schema的概念)
-
-
Redis数据库的操作
//1.切换数据库 (index是数据库编号,从0开始) select index //2.其他操作 quit ping //测试redis服务器是否连通 echo message //输入什么message,控制台就会输出什么message //3.数据移动 move key db //把key移动到db数据库中,原数据库不存在了(剪切操作) //4.数据清除 dbsize //看当前的数据库下有多少个数据 flushdb //删掉当前数据库下的所有数据 flushall //删掉所有数据库中的所有数据
五、Java连Redis服务
Java语言连接redis服务的工具有:Jedis、SpringData Redis、Lettuce等。其他语言也有自己连redis的工具
1. Jedis(Redis提供的工具)
-
Jedis:使用java语言连接redis服务
-
Jedis使用步骤
-
引入jedis的jar包—— redis.clients.jedis
-
写代码
- 连接redis
- 操作redis
- 关闭连接
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
@Test public void testJedis(){ //1.连接redis Jedis jedis = new Jedis("127.0.0.1", 6379); //2.操作redis jedis.set("name","itheima"); String name = jedis.get("name"); System.out.println(name); //3.关闭连接 jedis.close(); }
-
-
Jedis工具类开发
上述代码中,Jedis对象是手工管理的,不应该。
应该从Jedis连接池获取Jedis对象,而Jedis已经为我们提供好了连接池技术JedisPool
public class JedisUtils { private static JedisPool jedisPool = null; //把连接池的创建过程放在静态代码块中,就加载一次,也就创建一次 static { /** * JedisPool的三个参数 * 1.poolConfig:连接池配置对象 * 2.host:redis服务地址 * 3.port:redis服务端口号 */ JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); //设置最大连接数 jedisPoolConfig.setMaxTotal(30); //设置活动连接数 jedisPoolConfig.setMaxIdle(10); //设置redis服务地址 String host = "127.0.0.1"; //设置redis服务的端口号 int port = 6379; //定义一个Jedis连接池 jedisPool = new JedisPool(jedisPoolConfig, host, port); } public static Jedis getJedis() { //getResource()即获取Jedis对象 return jedisPool.getResource(); } //测试一下 public static void main(String[] args) { Jedis jedis = JedisUtils.getJedis(); } }
2. SpringData Redis (Spring提供的操作Redis)
位于spring-data-redis-x.x.x.jar包中,[Spring Data Redis官网](https://docs.spring.io/spring-data/redis/docs/current/reference/html/)。使用方法如下
-
引入jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
代码中
@Service public class LoginServiceImpl implements LoginService { @Autowired private RedisTemplate redisTemplate; …… //把token放在redis里,过期时间1天 ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set(key, value, 1, TimeUnit.DAYS); …… }