5.1 Redis
5.1.1 前言
前面使用到的mysql数据库会出现以下问题
由于用户量增大,请求数量也随之增大,数据压力过大
多台服务器之间数据不同步
多台服务器之间的锁,已经不存在互斥性了。
5.1.2 Redis
5.1.2.1 什么是Redis
Redis(Remote Dictionary Server)即远程字典服务,Redis是C语言编写,Redis是一款基于Key-Value的NoSQL(非关系型数据库),而且Redis是基于内存存储数据的.Redis还提供了多种持久化机制,性能可以达到110000/s读取数据以及81000/s写入数据,Redis还提供了主从,哨兵以及集群的搭建方式,可以更方便的横向扩展以及垂直扩展。
关系型数据库是基于关系表的数据库,最终会将数据持久化到磁盘上,而nosql数据库是基于特殊的结构,并将数据存储到内存的数据库。
从性能上而言,nosql数据库要优于关系型数据库,从安全性上而言关系型数据库要优于nosql数据库,所以在实际开发中一个项目中nosql和关系型数据库会一起使用,达到性能和安全性的双保证。
5.1.2.2 Redis优势
- redis是基于内存存储计算,性能速读远超mysql等数据库,计算速度很快,所以在使用的时候数据响应很快,
- redis支持多种多样的数据结构,如字符串、tree、ztree、map、等,这些丰富的数据结构,可以满足我们在开发工作大部分常见数据结构,进行存储。
- redis丰富的api支持,让我们在使用的时候,常见的查询存储都能够很方便的使用,支持自定的查询的api等等
- redis的生态比较成熟,很多家大型公司都在使用,很多相关的知识扩展以及分析
- redis分布式集群化扩展性极高,而且稳定,能够支撑大量的数据吞吐,只要硬件支持
5.1.2.3 Redis的启动与设置
5.1.2.3.1 前台显示形式启动
./redis-server
客户端
关闭服务
5.1.2.3.2 若要采用后台运行形式需修改配置
若采用后台运行需要修改相应配置文件
5.1.2.3.3 后台形式启动
由于软件安装位置为/usr/local,所以先进入/usr/local目录
进入redis-6.2.4目录
进入bin目录
启动服务端,注意这里的启动命令后带的redis.conf是我们前面为了后台形式启动所修改的配置文件,让启动命令运行指定的配置文件
启动客户端
5.2 Redis的数据类型
5.2.1
常用的5种数据结构:
- key-string:一个key对应一个值。
- key-hash:一个key对应一个Map。
- key-list:一个key对应一个列表。
- key-set:一个key对应一个集合。
- key-zset:一个key对应一个有序的集合。
另外三种数据结构:
- HyperLogLog:计算近似值的。
- GEO:地理位置。
- BIT:一般存储的也是一个字符串,存储的是一个byte[]。
value最常用的五种数据类型:
- 字符串(String):最常用的,一般用于存储一个值
- 列表(List):使用list结构实现栈和队列结构
- 集合(Set) :交集,差集和并集的操作
- 有序集合(sorted set) :排行榜,积分存储等操作
- 哈希(Hash):存储一个对象数据的
5.2.2 字符串(String)
set key value
设定key持有指定的字符串value,如果该key存在则进行覆盖操作,总是返回"OK"
setnx key value
只有在key不存在是添加
get key
获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息,因为get命令只能用于获取String value,如果该key不存在,返回null
getset key value
先获取该key的值,然后在设置该key的值。
incr key
将指定的key的value原子性的递增1.如果该key不存在,其初始值为0,在incr之后其值为1。如果value的值不能转成整型,如hello,该操作将执行失败并返回相应的错误信息。
decr key
将指定的key的value原子性的递减1.如果该key不存在,其初始值为0,在incr之后其值为-1。如果value的值不能转成整型,如hello,该操作将执行失败并返回相应的错误信息。
incrby key increment
将指定的key的value原子性增加increment,如果该key不存在,器初始值为0,在incrby之后,该值为increment。如果该值不能转成整型,如hello则失败并返回错误信息。
decrby key decrement
将指定的key的value原子性减少decrement,如果该key不存在,器初始值为0,在decrby之后,该值为decrement。如果该值不能转成整型,如hello则失败并返回错误信息。
append key value
如果该key存在,则在原有的value后追加该值;如果该key不存在,则重新创建一个key/value。
setex key seconds value
expire key seconds
过期时间
ttl
查看生存时长
5.2.3 列表(List)
lpush key value1 value2...
在指定的key所关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据。插入成功,返回元素的个数。
rpush key value1 value2…
在该list的尾部添加元素。
lrange key start end
获取链表中从start到end的元素的值,start、end可为负数,若为-1则表示链表尾部的元素,-2则表示倒数第二个,依次类推….
lpushx key value
当key存在时,在头部插入value,否则将不插入
rpushx key value
在key的尾部插入value
lpop key
返回并弹出指定的key关联的链表中的第一个元素,即头部元素。
rpop key
从尾部弹出元素。
rpoplpush resource destination
将链表中的尾部元素弹出并添加到头部。
llen key
返回指定的key关联的链表中的元素的数量。
lset key index value
设置链表中的index的脚标的元素值,0代表链表的头元素,-1代表链表的尾元素。
lrem key count value
删除count个值为value的元素,如果count大于0,从头向尾遍历并删除count个值为value的元素,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。
linsert key before|after pivot value
在pivot元素前或者后插入value这个元素。
5.2.4 集合(Set,不允许出现重复的元素)
sadd key value1 value2…
向set中添加数据,如果该key的值已有则不会重复添加。
smembers key
获取set中所有的成员。
scard key
获取set中成员的数量。
sismember key member
判断参数中指定的成员是否在该set中,1表示存在,0表示不存在或者该key本身就不存在。
srem key member1 member2…
删除set中指定的成员。
srandmember key
随机返回set中的一个成员。
sdiff key1 key2
返回key1中有但key2中无的成员,而且与key的顺序有关,即返回差集。
sdiffstore destination key1 key2
将key1、key2相差的成员存储在destination上。
sinter key[key1,key2…]
返回交集。
sinterstore destination key1 key2
将返回的交集存储在destination上。
sunion key1 key2
返回并集。
sunionstore destination key1 key2
将返回的并集存储在destination上
5.2.5 有序集合(sorted set)
zadd key score member score2 member2 …
将所有成员以及该成员的分数存放到sorted-set中。
zcard key
获取集合中的成员数量。
zcount key min max
获取分数在[min,max]之间的成员。
zincrby key increment member
设置指定成员的增加的分数。
zrange key start end [withscores]
获取集合中脚标为start-end的成员,[withscores]参数表明返回的成员包含其分数。
zrangebyscore key min max withscores
返回分数在[min,max]的成员并按照分数从低到高排序。[withscores]:显示分数;[limit offset count]:offset,表明从脚标为offset的元素开始并返回count个成员。
zrank key member
返回成员在集合中的位置。
zrem key member[member…]
移除集合中指定的成员,可以指定多个成员。
zscore key member
返回指定成员的分数。
5.2.6 哈希(Hash)
hset key field value
为指定的key设定field/value对(键值对)。
hgetall key
获取key中的所有filed-vaule。
hget key field
返回指定的key中的field的值。
hmset key fields
设置key中的多个filed/value。
hmget key fileds
获取key中的多个filed的值。
hexists key field
判断指定的key中的filed是否存在。
hlen key
获取key所包含的field的数量。
hincrby key field increment
设置key中filed的值增加increment,如:age增加20。
5.2.7 通用操作
keys patten
获取所有与patten匹配的key,*表示任意字符,?表示一个字符。
del key1 key2....
删除指定的key。
exists key
判断该key是否存在,1表示存在,0表示不存在。
rename key newkey
为当前key重命名。
expire key second
为当前key设置过期时间(单位:秒)。
ttl key
查看当前key剩余过期时间。
type key
查看当前key类型。
flushall
删除所有key
5.3 Jedis
Jedis:可以直接在IDEA中使用Redis
5.3.1 修改配置文件
修改/usr/local/redis-5.0.4/bin目录下的redis.conf配置文件,然后启动redis服务端
将绑定127.0.0.1注释掉,然后把保护模式关掉
如需设置密码,可以使用以下两种方式:
方式一:通过修改 redis.conf 文件,设置Redis的密码校验
requirepass 密码
方式二:在不修改 redis.conf 文件的前提下,在第一次链接Redis时,输入命令:Config set requirepass 密码
取消密码 Config set requirepass ''
后续连接redis客户端的时候,需要先 AUTH 做一下校验
127.0.0.1:6379> auth 密码
5.3.2 IDEA中创建对象
创建Maven工程,导入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer uid;
private String username;
private String password;
}
测试类
public class JedisDemo {
// 通过java程序访问redis数据库
// 获得单一的jedis对象操作数据库
@Test
public void test1() {
//获得连接对象
Jedis jedis = new Jedis("192.168.153.132", 6379);
//认证密码
//jedis.auth("root");
//获得之前redis中存储的数据
String name = jedis.get("name");
System.out.println(name);
//存储数据
jedis.set("password", "123");
System.out.println(jedis.get("password"));
//关闭
jedis.close();
}
//通过jedis的pool获得jedis连接对象
@Test
public void test2() {
// 创建池子的配置对象
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(30);// 最大闲置个数
poolConfig.setMinIdle(10);// 最小闲置个数
poolConfig.setMaxTotal(50);// 最大连接数
// 创建一个redis的连接池
JedisPool pool = new JedisPool(poolConfig, "192.168.153.132", 6379);
// 从池子中获取redis的连接资源
Jedis jedisPoolResource= pool.getResource();
// 创建User类进行存储
User user = new User(1001, "李四", "123");
// 将对象转换成json存储
jedisPoolResource.set("user", JSON.toJSONString(user));
String db_user = jedisPoolResource.get("user");
// 返回json数据
System.out.println(db_user);
// 返回User类型
System.out.println(JSON.parseObject(db_user,User.class));
// 关闭资源
jedis.close();
pool.close();
}
}
5.4 Redis事务
5.4.1 事务概述
Redis中的事务和MySQL中的事务有本质的区别,Redis中的事务是一个单独的隔离操作,事务中所有的命令都会序列化,按照顺序执行,事务在执行的过程中,不会被其他客户端发来的命令所打断,因为Redis服务端是个单线程的架构,不同的Client虽然看似可以同时保持连接,但发出去的命令是序列化执行的,这在通常的数据库理论下是最高级别的隔离。
Redis中的事务的作用就是串联多个命令,防止别的命令插队。
5.4.2 Redis事务命令
常用命令:multi、exec、discard、watch、unwatch
当输入multi命令时,之后输入的命令都会被放在队列中,但不会执行,直到输入exec后,Redis会将队列中的命令依次执行,discard用来撤销Exec之前被暂存的命令,并不是回滚。
watch/unwatch
在执行multi之前,先执行watch key1 [key2...] ,watch提供的乐观锁功能(初始时一个版本号,exec之后会更新当前版本号),在你exec的那一刻,如果被watch的键发生过改动,则multi到exec之间的指令全部不执行。
watch表示监控,相当于加锁,但在执行完exec时就会解锁。
unwatch取消所有锁。
5.4.3 Redis事务的特性总结
1.单独的隔离操作
事务中的所有命令都会序列化,然后按顺序执行,在执行过程中,不会被其他客户端发送的命令打断。
2.没有隔离级别的概念
队列中的命令没有被提交之前都不会执行。
3.不能保证原子性
Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,不会回滚