Redis入门
2.Redis简介
2.1 什么是redis?
2.2 Redis优缺点
2.3 redis-memcache与redis有什么区别?
3.Redis数量类型指令
3.1 String类型
3.2 hash类型
3.2 list类型
3.3 set类型
3.4 zset类型
7.Java redis应用
7.1jedis
7.2 lettuce
了解数据库分类
- 关系型数据库:Oracle,MySQL,SqlServer,DB2
- 非关系型的数据库(NoSql):
NoSql分类
- 键值存储(key,value) :Redis等
- 列存储数据库:HBase等
- 文档型数据库:MongoDb等
- 图形结构的数据库:Neo4J等
NoSql特点
- 数据模型比较简单
- 对数据库性能要求较高
- 不需要高度的数据一致性
- 需要灵活性更强的应用系统
- 对于给定key,比较容易映射复杂值的环境.
Redis简介
什么是redis?
redis是是以key-value形式存储的非关系型数据库,其性能极高,Redis能支持超过 10W次每秒的读写频率
redis定位是缓存,提高数据读写速度,减轻对数据库存储和访问压力
只要涉及缓存(临时存储),首选都是redis
Redis优缺点
优点:
- 对数据高并发读写(直接内存进行读写)
- 对海量数据的高效率存储和访问
- 对数据的可拓展性和高可用性
- 单线程操作,每个操作都是原子性操作 (Redis 6 外界多线程排队等待)
缺点:
- redis(ACID处理非常简单)
- 无法做太复杂的关系数据库模型
redis安装,目前官方版本已经6.0.6版本,windows还是3.2(大神没有更新)
项目操作涉及到缓存操作:redis-memcache --拓展
redis-memcache与redis有什么区别?
什么是memcache?
Memcache是一个高性能,分布式于内存对象中的缓存系统,能够存储包括图像,文件,sql语句结果等数据.使用K-V形式的方式来存储数据,查询的效率高,协议简单.
区别
redis | memcache | |
---|---|---|
数据操作不同 | Redis支持的数据类型丰富list,set,hash等 | 只支持简单的key-value存储 |
内存管理机制不同 | redis有部份存在硬盘上,这样能保证数据的持久性,支持数据的持久化 | memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小 |
性能不同 | Redis只使用单核 | Memcached可以使用多核,Memcached性能要高于Redis |
value 值大小不同 | Redis 最大可以达到 1GB | memcache 只有 1MB |
集群管理不同 | Redis更偏向于在服务器端构建分布式存储 | Memcached只能采用客户端实现分布式存储 |
- 使用底层模型不同:它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。redis有自己构建VM 机制
- 应用场景:Memcached:动态系统中减轻数据库负载,提升性能;做缓存;Redis:适用于对读写效率要求都很高,数据处理业务复杂和对安全性要求较高的系统
引用参考文章:
Memcache与Redis有什么区别
Redis和Memcache区别,优缺点对比
Redis数量类型指令
1.String类型 Map<String, String> map
set key value
:存入键值对get key
: 根据键取出值incr key
: 把值递增1decr key
: 把值递减1del key
: 根据键删除键值对setex key timeout value
:存入键值对,timeout表示失效时间,单位sttl key
:可以查询出当前的key还剩余多长时间过期- setnx key value : key存在不添加,key不存在添加
应用场景:
1.计数器 :能够快速实现技术,查询缓存的功能
2.共享session [[每次获得用户更新信息/登录信息等从redis获取]
2.hash类型 Map<string, Map<string, ?>> map
hset key hashkey hashvalue
: 存入一个hash对象hget key hashkey
: 根据hash对象键取去值hexists key hashkey
: 判断hash对象是含有某个键hdel key hashkey
: 根据hashkey删除hash对象键值对hincrby key hashkey 递增值
: 递增hashkey对应的值hkeys key
: 获取hash对象的所有键hvals key
: 获取hash对象的所有值hgetall key
: 获取hash对象的所有数据
3.list类型 Map<String, List>
List :类似java中的(双向)队列,是一个链表结构的集合
rpush key value
: 往列表右边添加数据lrange key start end
: 范围显示列表数据,全显示则设置0 -1lpush key value
: 往列表左边添加数据lpop key
: 弹出列表最左边的数据rpop key
: 弹出列表最右边的数据llen key
: 获取列表长度
应用场景
用户收藏文章列表 article:id [aid1,aid2,aid3]
4.set类型
sadd key value
: 往set集合中添加元素smembers key
: 列出set集合中的元素srem key value
: 删除set集合中的元素spop key count
: 随机弹出集合中的元素sdiff key1 key2
: 返回key1中特有元素(差集)sinter key1 key2
:返回两个set集合的交集sunion key1 key2
: 返回两个set集合的并集scard key
: 返回set集合中元素个数
应用场景 :去重
5.zset类型
zadd key score column
: 存入分数和名称zincrby key score column
: 偏移名称对应的分数zrange key start end
: 按照分数升序输出名称zrevrange key start end
: 按照分数降序输出名称zrank key name
: 升序返回排名zrevrank key name
: 降序返回排名zcard key
: 返回元素个数
应用场景:排行榜
什么时候使用对应类型
如果确定使用redis, 此时需要考虑使用哪个数据类型
1.如果要排序选用zset
2.如果数据是多个且允许重复选用list
3.如果数据是多个且不允许重复选用set
4.剩下的使用string
怎么设计key与value值
key
- 唯一性
- 可读性
- 灵活性
- 时效性
value:根据 需求决定
redis进阶
redis高级命令(全局)
key *
:返回所有key (可以模糊查询 key h*, h开头的key)exists
:是否存在指定keyexpire
:设置某个key的过期时间(已存在的key),使用ttl查看剩余时间persist
:取消过期时间flushdb
:清空当前数据库,flushall
清空所有数据库
redis安全性
redis权限密码设置
修改对应配置文件redis.windows-service.conf
,把# requirepass foobared
把#注释去掉 ,foobared修改为自己的密码,重启redis服务,使用
**redis-cli -a [密码]**指令进入redis操作,如果设置了密码,没有输入直接进行操作会报错(error)NOAUTH Authentication required.
redis事务
redis事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制.Redis中一个事务从开始到执行会经历 开始事务 、 命令入队 和 执行事务 三个阶段,Redis是不支持回滚
- multi方法打开事务
- exec执行
- discard方法取消事务
redis持久化机制
启动redis服务时,去到硬盘中加载数据 ,刚开始内存是没有数据,我们添加到内存中,redis会按照某种规则添加(持久化)到硬盘中
redis持久化两种方式:
- RDB (快照) :默认,snapshotting.将内存中以快照的方式写入到二进制文件中,可以进行配置设置持久化方式
Snapshotting设置:
save 900 1 #900秒内如果超过1个Key被修改则发起快照保存
save 300 10 #300秒内如果超过10个key被修改,则发起快照保存
save 60 10000
- AOF(拼接):AOF比快照方式有更好的持久化性,快照方式在一定时间间隔可能会发生数据丢失情况,使用AOF,redis会将每一个收到的写命令都通过write函数追加到命令中,重启时,会重新执行命名重建数据库内容(相当于ctrlC+ctrlV)
aof设置
appendonly yes //启动aof持久化方式有三种修改方式
#appendfsync always//收到命令就立即写到磁盘,效率最慢.但是能保证完全的持久化
#appendfsync everysec//每秒写入磁盘一次,在性能和持久化方面做了很好的折中
#appendfsync no //完全以依赖os 性能最好,持久化没保证
redis内存淘汰机制以及过去key处理
内存淘汰机制 ,四大类:
- LRU:短时间内没有使用的数据干掉
- LFU:最不经常使用的,使用次数最少与频次有关
- TTL:设置了过期时间的部分数据,快过期提前一点把你干掉
- 随机淘汰:全凭天命,阎王要你三更走,你就不能留到五更
过期key的清除操作,三种策略
- 惰性删除:当key多期,下次来访问时,判断是否过期,过期删除
- 定时删除:设置key的过期时间,到点删除
- 定期删除:隔一段时间,对数据进行检查,通过算法删除过期key
Java redis应用
java对redis常用的有两种jedis与lettuce
jedis
1.导入对应依赖
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2.API test
- String
public class TestStringJedis {
@Test
public void testJedis() {
// 1:创建Jedis连接池
JedisPool pool = new JedisPool("localhost", 6379);
// 2:从连接池中获取Jedis对象
Jedis jedis = pool.getResource();
/* 设置密码
jedis.auth(密码); */
// 3:TODO
/**String**/
jedis.set("name","xuan");
jedis.set("age","18");
jedis.set("delkey","hhhh");
System.out.println(jedis.get("name"));
// age+1
jedis.incr("age");
System.out.println(jedis.get("age"));
//age -1
jedis.decr("age");
System.out.println(jedis.get("age"));
//del
//jedis.del("delkey");
//设置失效时间 ,查询还剩多少时间
//jedis.setex("love",30,"520");
System.out.println(jedis.ttl("love"));
//setnx ,如果不存在key直接添加
jedis.setnx("name1","setnxdemo");
//全局 获取所有key
System.out.println(jedis.keys("*"));
/**
*
*/
System.out.println(jedis);
// 4:关闭资源
jedis.close();
pool.destroy();
}
- hash
jedis.hset("emps","age","18");
jedis.hset("emps","kk","qq");
System.out.println(jedis.hget("emps", "age"));
//age+1
jedis.hincrBy("emps","age",1);
System.out.println(jedis.hget("emps", "age"));
//判断是否存在
System.out.println(jedis.hexists("emps", "name")); //true
//删除 dept中的name
jedis.hdel("dept","name");
System.out.println(jedis.hget("dept", "name"));
//全局 获取所有key
System.out.println(jedis.keys("*"));
-
List
/**List**/ jedis.rpush("name","php","java","go","python"); System.out.println(jedis.lrange("name", 0, -1)); //[php, java, go, python] //往左边添加数据 //jedis.lpush("name","xuan"); System.out.println(jedis.lrange("name", 0, -1)); //[xuan, php, java, go, python] //从左边弹出数据 System.out.println(jedis.lpop("name")); //弹出xuan [php, java, go, python] //从右边弹出数据 System.out.println(jedis.rpop("name")); //弹出 python [php, java, go] //获取列表长度 System.out.println(jedis.llen("name")); //3
-
Set
/**Set**/
//添加
jedis.sadd("name","yue","xuan","dong","hao","ying");
//列出set中的元素
System.out.println(jedis.smembers("name")); //[yue, xuan, hao, dong, ying]
//随机弹出元素
System.out.println(jedis.spop("name")); //yue
//删除集合中的元素
jedis.srem("name", "xuan");
System.out.println(jedis.smembers("name")); //[ying, dong, hao]
jedis.sadd("set1","1","2","3","4");
jedis.sadd("set2","6","5","3","4");
//比较两个集合的不同 set1相比于set2哪里不同 差集
System.out.println(jedis.sdiff("set1", "set2")); //[2, 1]
//交集
System.out.println(jedis.sinter("set1", "set2")); //[3, 4]
//并集
System.out.println(jedis.sunion("set1", "set2")); //[1, 2, 3, 4, 5, 6]
//返回指定集合的元素个数
System.out.println(jedis.scard("set1"));
- ZSet
/**ZSet**/
//jedis.zadd("score",80,"xuan");
//jedis.zadd("score",60,"tian");
//jedis.zadd("score",100,"yue");
//按照分数升序排序
System.out.println(jedis.zrange("score", 0, -1)); //[tian, xuan, yue]
///按照分数 降序排序
System.out.println(jedis.zrevrange("score", 0, -1)); //[yue, xuan, tian]
//偏移名称对应的分数
// System.out.println(jedis.zincrby("score", 10, "xuan")); //xuan --90.0
//升序返回排名 从0开始
System.out.println(jedis.zrank("score", "xuan"));
//降序,返回排名
System.out.println(jedis.zrevrank("score", "xuan"));
//返回元素个数
System.out.println(jedis.zcard("score"));
lettuce
Springboot底层 默认是lettuce
Springboot-redis api方法 是redis命令全称,全局命令:封装在 对象中
1.改造成Springboot,配置对应依赖
<!--Springboot集成redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.API test
- String
@SpringBootTest
public class TestRedis {
//@Autowired
//private RedisTemplate<String,Object> template;
@Autowired
private StringRedisTemplate template;
@Test
public void RedisTest(){
//操作String
//template.opsForValue().set("name","xuan");
//template.opsForValue().set("age","18");
//template.opsForValue().set("qqq","15");
System.out.println(template.opsForValue().get("name"));
//increment age+1
System.out.println(template.opsForValue().increment("age")); //19
//decrement age -1
System.out.println(template.opsForValue().decrement("age"));
//设置key的过期时间 参数2:时间 ,参数3:时间单位
// template.expire("qqq",30, TimeUnit.SECONDS);
//获取剩余时间
System.out.println(template.getExpire("qqq"));
//全局命令
//获得所有key
System.out.println(template.keys("*"));
}
}
- Hash
//操作hash
template.opsForHash().put("emps","name","xuan");
template.opsForHash().put("emps","age","18");
template.opsForHash().put("emps","course","java");
System.out.println(template.opsForHash().get("emps", "course")); //java
// increment age +1
//System.out.println(template.opsForHash().increment("emps", "age", 1));
//判断是否有该 key 和字段
System.out.println(template.opsForHash().hasKey("emps", "qqq"));
//返回所有字段
System.out.println(template.opsForHash().keys("emps")); //[name, age, course]
//返回value
System.out.println(template.opsForHash().values("emps")); //[xuan, 19, java]
//删除
template.opsForHash().delete("emps", "course");
- List
//操作List
template.opsForList().rightPush("name","php");
template.opsForList().rightPush("name","java");
template.opsForList().rightPush("name","go");
//template.opsForList().rightPushAll("age","18","20","19");
System.out.println(template.opsForList().range("name", 0, -1)); //[php, java, go]
System.out.println(template.opsForList().range("age", 0, -1)); //[18, 20, 19]
//弹出左边
//emplate.opsForList().leftPop("name");
System.out.println(template.opsForList().range("name", 0, -1)); //[java, go]
//获得长度
System.out.println(template.opsForList().size("name"));
//删除
template.opsForList().remove("age",1,"18");
System.out.println(template.opsForList().range("age", 0, -1));
- Set
//操作Set
//添加
template.opsForSet().add("name","yue","xuan","dong","hao","ying");
//获取
System.out.println(template.opsForSet().members("name")); //[yue, xuan, hao, dong, ying]
template.opsForSet().add("set1","1","2","3","4","5");
template.opsForSet().add("set2","8","7","6","4","5");
//差集
System.out.println(template.opsForSet().difference("set1", "set2")); //[1, 2, 3]
//交集
System.out.println(template.opsForSet().intersect("set1", "set2")); //[4, 5]
//并集
System.out.println(template.opsForSet().union("set1", "set2")); //[1, 2, 3, 4, 5, 6, 7, 8]
//随机弹出数据
System.out.println(template.opsForSet().pop("name")); //ying
//获取长度
System.out.println(template.opsForSet().size("name"));
- ZSet
//操作ZSet
template.opsForZSet().add("score","y",80);
template.opsForZSet().add("score","x",70);
template.opsForZSet().add("score","q",60);
template.opsForZSet().add("score","a",50);
//按照分数升序
System.out.println(template.opsForZSet().range("score", 0, -1)); //[a, q, x, y]
//按照分数倒序
System.out.println(template.opsForZSet().reverseRange("score", 0, -1)); //[y, x, q, a]
//升序返回排名,从0开始
System.out.println(template.opsForZSet().rank("score", "x")); //2
//返回元素个数
System.out.println(template.opsForZSet().zCard("score"));