一.Redis介绍
说明:此文档主要内容是B站上的一个Redis入门教程的一个笔记记录
1.1引言
1.1.1现实需求与矛盾
1.由于用户量增大,请求数量增大,数据压力过大
2.多台服务器数据不同步
3.多台服务器的锁不存在互斥性
1.1.2解决方案
1.Redis是基于内存存储和读取数据的
2.可以将之前存放在session中的共享数据统一存放在Redis中
3.Redis基于用户请求是单线程的
1.2NoSQL介绍
NoSQL,(Not Only SQL),可以理解为非关系型数据库,区别于关系型数据库,只是做一个区分,主要分为:
1.key-value :Redis
2.文档型数据库:Slor,Mongodb
3.面向列:Hbase
4.图形化:Neo4j
1.3Redis介绍
Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
二.Redis安装
2.1安装Redis
在csdn找教程,github,镜像网站与官网找安装包与教程操作
尽量在Linux虚拟机上安装
version:5.0.7
image:daocloud.io/library/redis:5.0.7
restart:always
container_name:redis
envirment:
-TZ=Aisa/Shanghai
ports:
-6379:6379
安装图形化用户界面,gitHub
2.2连接Redis
windows环境下一键安装后,在命令行界面输入命令启动服务,操作细节就不再多赘述,没有加入Path路径下使用命令要先到Redis安装目录下
执行以下命令
redis-server.exe redis.windows.conf
出现以下界面表示成功
注意事项:
服务启动后不能关掉CMD窗口,关闭后redis服务也会同时关闭。为了方便可以将redis添加到Windows服务中,添加命令如下
redis-server.exe --service-install redis.windows.conf --loglevel verbose
常用命令:
停止服务
redis-server --service-stop
启动服务
redis-server --service-start
客户端启动
redis-cli
2.3使用图形界面
下载安装redis desktop manager,新版本收费,在github上可以找到收费之前的版本。也可以选择其他的工具,一键安装,连接也很简单
三.Redis常用命令
3.1 Redis存储数据的结构
3.1.1.key-string:一个key对应一个值(最常用)
3.1.2.key-hash:一个key对应一个map(对象数据)
3.1.3.key-list:一个key对应一个列表(可以实现栈和队列)
3.1.4.key-set:一个key对应一个集合(并,差,交的操作)
3.1.5.key-zset:一个key对应一个有序集合(排行榜,积分存储)
3.2 string常用命令
#1.添加值
set key value
#2.取值
get key
#3.批量操作
mset key value [key value ...]
mget key [key ...]
#4.自增命令(自增1)
incr key
#5.自减命令(自减1)
decr key
#6.自增或自减指定数量
incrby key increment
decrby key increment
#7.设置值的同时指定生存时间(添加数据时尽量设置生存时间)
setex key second value
#8.设置值,若当前key存在,什么也不做,否则添加
setnx key value
#9.在key对应的value后,追加内容
append key value
#10.查看value字符串的长度
strlen key
3.3 hash常用命令
#1.存储数据
hset key field value
#2.获取数据
hget key field
#3.批量操作
hmset key field value [field value ...]
hmget key field [field ...]
#4.自增(指定大小),不要对字符串类型自增
hincrby key field increment
#5. 设置值,若key - field不存在,添加,反之什么也不做
hsetnx key field value
#6.检查field是否存在
hexists key field
#7.删除key对应的某一个或多个field
hdel key field [field]
#8.获取当前hash结构中全部的field和value
hgetall key
#9.获取全部的field
hkeys key
#10.获取全部value
hvals key
#11.获取field数量
hlen key
3.4 list常用命令
#1.存储数据(l左侧插入,r右侧插入)
lpush key value [value ...]
rpush key value [value ...]
#2.验证插入(key不存在,undo,key存在且为list结构时,插入)
lpushx key value
rpushx key value
#3.指定索引插入(会覆盖原来索引元素值,类似数组操作)
lset key index value
#4.弹栈方式获取数据(获取并移除,类似出栈)
lpop key
rpop key
#5.指定索引范围数据(与python索引结构类似,正数左起始,负数右起始)
lrange key start stop
#6.获取指定索引数据
lindex key index
#7.获取列表长度
llen key
#8.删除列表数据(删除count个数的value值,count为正,左边删,负,右边删,count==0,删除全部数据)
lrem key count value
#9.保留指定索引范围类得数据,超出部分移除
ltrim key start stop
#10.将一个列表的最后一个数据放到另一个列表的头部(原子操作)
rpoplpush list1 list2
3.5 set常用命令
#1.存储数据
sadd key member [member ...]
#2.获取数据(全部)
smembers key
#3.随机获取一个数据(获取并移除,默认弹一个)
spop key [count]
#4.多个set取交集
sinter set1 set2 ...
#5.并集(所有集合的去重)
sunion set1 set2 ...
#6.差集(多个集合不一样的数据,注意运算顺序)
sdiff set1 set2 ...
#6.删除数据(支持批量操作)
srem key member [member...]
#7.查看集合是否包含某个值
sismember key member
3.6 zset常用命令
#1.添加数据
zadd key score member [score member ...]
#2.修改score(member存在于key,正常增加,不存在,实现添加)
zincrby key increment member
#3.查看指定member的score
zscore key member
#4.获取zset中数据的量
zcart key
#5.根据score得范围查询member的数量(左右取闭区间)
zcount key min max
#6.删除zset中的成员
zrem key member [member...]
#7.根据score升序,获取指定范围内数据(加withscores后会返回score+member,不加返回member)
zrange key start stop [withscores]
#8.降序
zrevrange key start stop [withscores]
#9.根据score的范围获取数据(limit参数部分类似mysql,加(表示开区间,)表示闭区间,最大值+inf,最小值-inf)
zrangebyscore key min max [withscores] [limit offset count]
#10.根据score的范围获取数据(参数位置改变)
zrangebyscore key max min [withscores] [limit offset count]
3.7 key的常用命令
#1.查看全部key(pattern:*,xxx*,*xxx.通配符)
keys pattern
#2.查看某个key是否存在(1,存在;0,不存在)
exists key
#3.删除key(支持批量操作)
del key [key...]
#4.设置key的生存时间(秒,毫秒级别)
expire key second
pexpire key milliseconds
#5.设置key的生存时间(到某一个时间点,单位为s,ms)
expireat key timestamp
pexpireat key milliseconds
#6.查看key的剩余生存时间(单位s,ms,-2当前key不存在,-1未设置生存时间,否则返回具体剩余时间)
ttl key
pttl key
#7.移除key的生存时间(1-移除成功;0-key不存在生存时间或key不存在)
persist key
#8.选择操作的库(共有16个库,默认0号库)
select 0~15
#9.移动key到另外一个库中
move key db
3.8 库的常用命令
#1.清空当前所在的库
flushdb
#2.清空全部数据库
flushall
#3.查看当前所在库有多少个key
dbsize
#4.查看最后一次操作的时间(保存在磁盘上的时间)
lastsave
#5.实时监控Redis服务收到的目录
monitor
四.Java连接Redis
有Jedis 连接Redis与Lettuce连接,使用Jedis,其方法对应redis基础命令操作
4.1 Jedis连接Redis
-
创建maven项目
-
导入依赖(Jedis,junit,lombok,spring-context,fastjson)
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <encoding>UTF-8</encoding> <java.version>15</java.version> <maven.compiler.source>15</maven.compiler.source> <maven.compiler.target>15</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.6.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.58</version> </dependency> </dependencies>
-
测试
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class Demo1Test {
@Test
public void testConnection() {
//1.连接redis,使用的是本地主机
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.操作redis,redis的命令是什么,jedis的方法就是什么
jedis.set("Hello","World");
jedis.set("redis","success");
//3.释放资源
jedis.close();
}
}
连接与写入
@Test
public void testGet(){
//1.连接redis
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.操作redis,redis的命令是什么,jedis的方法就是什么
String hello = jedis.get("Hello");
String redis = jedis.get("redis");
System.out.println("Hello的值:"+hello);
System.out.println("redis的值:"+redis);
//3.释放资源
jedis.close();
}
获取成功
4.2Jedis存储对象到redis中,以字节数组
import com.lisanbian.pojo.Person;
import org.junit.Test;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.Jedis;
public class Demo2Test {
@Test
public void storeObjectTest(){
//1.连接
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.准备key和value
String key = "user";
Person value = new Person("李三变","男",22,"上海");//要实现序列化接口
//3.转化为字节数组,需要导入一个工具依赖,spring-context,方便转化
byte[] byteKey = SerializationUtils.serialize(key);
byte[] byteValue = SerializationUtils.serialize(value);
//4.写到redis中
jedis.set(byteKey,byteValue);
//5.释放连接资源
jedis.close();
}
}
保存结果
获取对象
import com.lisanbian.pojo.Person;
import org.junit.Test;
import org.springframework.util.SerializationUtils;
import redis.clients.jedis.Jedis;
public class Demo3Test {
@Test
public void getObject(){
//1.连接
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.准备key
String key = "user";
//3.将key转化为字节数组
byte[] byteKey = SerializationUtils.serialize(key);
//4.根据key获取value
byte[] byteValue = jedis.get(byteKey);
//5.反序列化得到value的对象,需要强制类型转换
Person value = (Person)SerializationUtils.deserialize(byteValue);
System.out.println(value.toString());//字符打印输出,验证正确与否
//6.释放连接资源
jedis.close();
}
}
获取解析成功
4.3存储对象到redis,以String形式
import com.alibaba.fastjson.JSON;
import com.lisanbian.pojo.Person;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class Demo4Test {
@Test
public void saveObjectByString(){
//1.获取连接
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.准备key与value(Person对象)
String key = "user2";
Person person = new Person("张三","女",21,"北京");
//3.将value转化为json字符串,需导入fastjson依赖
String value = JSON.toJSONString(person);
//4.存入redis
jedis.set(key,value);
//5.关闭连接
jedis.close();
}
}
结果
获取
import com.alibaba.fastjson.JSON;
import com.lisanbian.pojo.Person;
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class Demo5Test {
@Test
public void getJsonToObject(){
//1.获取连接
Jedis jedis = new Jedis("127.0.0.1",6379);
//2.准备key
String key = "user2";
//3.获取值,直接返回json/转换成Person对象
String value = jedis.get(key);
Person user = JSON.parseObject(value,Person.class);//将json字符串转化为对象
//4.返回或输出
System.out.println(user);
//5.关闭连接
jedis.close();
}
}
结果
4.4 Jedis连接池
池化思想,当需要频繁重复获取一个资源时,便将一定资源事先创建好,以供随时取用
使用连接池获取连接,相对于频繁创建和释放连接,更节省资源,这些资源其实都是通过底层系统提供的系统资源,不适合频繁创建销毁,会消耗大量系统资源
简单创建
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class Demo6Test {
//通过连接池获取连接
@Test
public void getConnFromPool(){
//1.创建连接池
JedisPool jedisPool = new JedisPool("127.0.0.1",6379);
//2.获取Jedis对象
Jedis jedis = jedisPool.getResource();
//3.业务操作
String value = jedis.get("Hello");
System.out.println(value);
//4.释放资源,即放回连接池
jedis.close();
}
}
高级创建,指定配置信息
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class Demo7Test {
@Test
public void getConnFromPoolPlus(){
//1.创建连接池配置信息
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//相关参数,可以根据实际情况指定合理的数量
/*
默认配置
public static final int DEFAULT_MAX_TOTAL = 8;
public static final int DEFAULT_MAX_IDLE = 8;
public static final int DEFAULT_MIN_IDLE = 0;
private int maxTotal = 8;最大活跃数
private int maxIdle = 8;最大空闲数
private int minIdle = 0;最小空闲数
*/
poolConfig.setMaxTotal(20);
poolConfig.setMaxIdle(10);
poolConfig.setMinIdle(1);
//2.创建连接池
JedisPool jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379);
//3.获取Jedis对象
Jedis jedis = jedisPool.getResource();
//4.业务操作
String value = jedis.get("Hello");
System.out.println(value);
//5.释放资源,即放回连接池
jedis.close();
}
}
4.5 Redis管道操作
说明:操作Redis时,执行一个命令需要先发送请求到Redis服务器,此过程要经历网路延迟,Redis同时也要给客户端一个响应。
通过Redis的管道,可将命令放到客户端的一个Pipeline中,之后一次性将命令都发送到Redis服务,Redis服务一次性将返回结果返回给客户端。
主要节省的是多次建立网络通信时间
单个命令与管道操作对比
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
public class Demo8Test {
@Test
public void singleLine(){
JedisPool jedisPool = new JedisPool("127.0.0.1",6379);
Jedis jedis = jedisPool.getResource();
//执行100000次自增操作,记录时间
long start = System.currentTimeMillis();
for(int i = 0;i<100000;i++){
jedis.incr("single");
}
jedis.close();
//打印执行时间
System.out.println(System.currentTimeMillis()-start);//3244ms
}
@Test
public void pilpline(){
JedisPool jedisPool = new JedisPool("127.0.0.1",6379);
Jedis jedis = jedisPool.getResource();
//创建管道
Pipeline pipeline = jedis.pipelined();
//执行100000次自增操作将其放到管道中,记录时间
long start = System.currentTimeMillis();
for(int i = 0;i<100000;i++){
pipeline.incr("pip");
}
//执行命令
pipeline.syncAndReturnAll();
jedis.close();
//打印执行时间
System.out.println(System.currentTimeMillis()-start);//326ms
}
}
//简单评测:
//100000次操作
//3244/326=9.950920245398773,效率提升几乎十倍
//继续测试1000000次操作
//22299/2652 = 8.408371040723981,效率提升接近8.5倍
//效率提升非常明显
五.Redis其他配置及集群(下一篇)
此部分因自身环境问题,省略了许多细节
修改yml文件,以方便后期修改Redis配置信息
指定Redis的配置文件