Redis
NOSQL数据库分类
键值存储:
这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署
代表: Redis
列存储数据库:
这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。
代表: HBase
文档型数据库:
文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高
代表: MongoDb
图形数据库
什么是Redis
Redis是以键值对的形式存储,和传统数据库不一样,不一定遵守传统数据库的基本要求
优点以及作用:
对数据进行高并发的读写,对海量数据的高效率存储和访问
提高数据的可拓展性和可用性
单线程操作每个操作都是原子操作.没有并发的相关问题
redis的定位
** 定位是缓存,提高数据的读写速度,减轻在访问的时候对数据库的压力**
redis的缺点:
没有办法做复杂关系型的数据库
优势
性能极高redis支持超过10w次每秒的读写速度
Redis数据类型
Redis命令格式:
类型命令 key 参数数据
set name aaa
String类型
String类型包含多种类型的特殊类型,是二进制安全的,序列化的对象进行存储
类型命令 key 参数数据 常用的命令
set key value -> 存入键值对
get key -> 根据键取出值
incr key -> 把值递增1
decr key -> 把值递减1
del key -> 根据键删除键值对
setex key timeout value -> 存入键值对,timeout表示失效时间,单位s
ttl key->可以查询出当前的key还剩余多长时间过期
setnx key value -> 如果key已经存在,不做操作, 如果key不存在,直接添加
应用场景
计数器:快速计算数据,查询缓存
共享session:处于负载均衡的考虑,用redis将用户session集中管理,
在这种模式下只要保证redis的高可用和扩展性的,每次获取用户更新或查询登录信息
都直接从redis中集中获取。
hash类型
hash类型是String类型的field和value的映射表,或者说是一个String的集合,它特别适合存储对象
相对于String占用空间更小,方便存储整个对象
常用指令
hset key hashkey hashvalue -> 存入一个hash对象
hget key hashkey -> 根据hash对象键取去值
hexists key hashkey -> 判断hash对象是含有某个键
hdel key hashkey -> 根据hashkey删除hash对象键值对
应用场景
可以用来对用户的信息管理,但是哈希类型和关系型数据库有所不同,哈希类型是稀疏的,
共享session:
key:user_token
value:
class User{
private String userame;
private String password;
private int age;
}
user(“dafei”, “666”, 18)
-------------------------------------
方案1: 将user对象转换json格式字符串存redis 【侧重于查, 改非常麻烦】
key value
list类型
Redis中的list类型跟java中的集合操作
它是一个链表结构的集合,其主要的功能主要有push,pop,这个类型是一个双端链表结构,通过操作,可以在头或者尾部进行添加或者删除元素,list又可以作为栈使用,还可以作为队列使用
Map<String, List>
rpush key value -> 往列表右边添加数据
lrange key start end -> 范围显示列表数据,全显示则设置0 -1
lpush key value -> 往列表左边添加数据
lpop key -> 弹出列表最左边的数据,就是相当于删除最左边的数据,然后第二个进行顶替
rpop key -> 弹出列表最右边的数据,同上
llen key -> 获取列表长度
set类型
这个类型存储的时候是无序的
如何选用数据类型
1>如果排序的功能选用zset
2>如果数据是多个并且允许重复使用选用list
3>如果数据是多个且不允许重复,选用set
4>剩下的选用String
5>如果是对象类型可以使用hash类型
hash —> 转换成json格式
{
key1:value1
key2:value2 ------> “{key1:value1, key2:value2}”
}
JSON.toJsonString(map)
有些公司约定key和value必须使用字符串,这时候
排序选用zset,其他的使用String
所以有些公司统一规范, 统一使用字符串, 减少泛型操作
Listlist = …
Set set = …
Map<String, Object> map = …
key和value的设计
key的设计:
1:唯一性
2:可读性
3:灵活性
4:时效性
value值根据需求决定
redis高级指令
返回满足所有的键
keys *(模糊查询,查询所有的key)
exisit (是否存在指定的key)
expire 设置某个key的存活时间,使用ttl查看剩余的存活时间
persist 取消设置的存活时间,这个需要在存活结束之前取消,要不然就是没有效果
flushdb 清空当前的数据库,fiushal清空所有的数据库
dbsize查看数据库key的数量
redis事务
redis的的事务非常简单,使用方法: 首先是使用multi方法打开事务,然后进行设置,这时候设置的数据会放到队列里进行保存,最后使用exec执行,把数据依次存储到redis中,使用discard方法取消事务
redis持久化机制
RDB方式和AOF方式
RDB方式是快照方式,将内存中以快照的方式写入到二进制文件中,.默认为dump.rdb.可以自己配置快照的自动化方式,定制在n秒内超过修改了m个key然后就进行快照,
ave 900 1 #900秒内如果超过1个Key被修改则发起快照保存
save 300 10 #300秒内如果超过10个key被修改,则发起快照保存
AOF方式是append–only–file缩写,快照的方式不是因为是一段时间进行存储一次,这样的话服务器重启的时候很可能会造成数据的丢失,AOF虽然也不是直接存储到硬盘中,但是可以通过强制修改的方法写到硬盘中
aof设置:
appendonly yes //启动aof持久化方式有三种修改方式
#appendfsync always//收到命令就立即写到磁盘,效率最慢.但是能保证完全的持久化
#appendfsync everysec//每秒写入磁盘一次,在性能和持久化方面做了很好的折中
#appendfsync no //完全以依赖os 性能最好,持久化没保证
redis淘汰机制
服务器就算再大也会有用完的时候,这时候就会删除key
常见的四种方式:
1: LRU:LRU是least recently used,意思近期较少使用,简单理解就是从数据库中删除那些最少访问,长期不使用的key
2:LEU:Least Frequently Used,用的最少,跟上面基本一个意思,使用次数最少,
3:TTL:就是那些设置的时间限制,存活时间的,反正都要退休,干脆直接删除
4:随机淘汰:就是随机去淘汰,生死有命富贵在天
redis实际使用
jedis基本使用:
// 1:创建Jedis连接池
JedisPool pool = new JedisPool("localhost", 6379);
// 2:从连接池中获取Jedis对象
Jedis je = pool.getResource();
/* 设置密码*/
je.auth("admin");
//-------------------String类型--------------------
je.set("name","dagfei");
je.set("age","12");//设置键值对
System.out.println(je.incr("age"));//递增
System.out.println(je.get("name"));//获取key对应的value
System.out.println(je.decr("age"));//递减一
System.out.println("删除"+je.del("age"));//删除某个key
// je.setex("age",100,"22");//设置存活时间
System.out.println(je.ttl("age"));//查看存活时间
Long age = je.setnx("age", "12");//如果已经有这个key值不做改变,返回0,如果没有直接添加
System.out.println(age);
System.out.println("-------------------hash类型--------------------");
je.hset("user","name","ben");
// je.hset("user","age","12");
je.hset("test","age","12");//设置对象类型的键值,key对象对应的value是属性key和值value
System.out.println(je.hget("user","age"));
System.out.println("是否包含"+je.hexists("user", "h"));
System.out.println("是否包含"+je.hexists("user", "name"));//检查是否包含这个hashkey
System.out.println("0是成功删除"+je.hdel("user","age"));//通过hashkey删除键值对,这个删除的相当于对象里面的属性字段
System.out.println("-------------------list类型--------------------");
// je.lpush("game","地平线","GTAV","剑灵","战地");
// je.rpush("game","右边添加");//在左边或者在右边添加
System.out.println("查看所有数据"+je.lrange("game", 0, -1));//0---(-1)代表的是查询所有,想要查询对应的数据可以根据对应的索引区间查找
// System.out.println(je.lpop("game"));//删除/弹出最左边的数据
// System.out.println(je.rpop("game"));//删除/弹出最右边的数据
System.out.println("长度"+je.llen("game"));//度就是索引的值
// System.out.println(je.ltrim("game", 10, 20));//截取对应的长度
je.set("name", "aaa");
System.out.println("-------------------set类型--------------------");
// je.sadd("number","1","2","3","4","5");
// je.sadd("number","6");
// je.sadd("number","7");
// je.sadd("number","a","b","c","d");
System.out.println("je.smembers(\"bnumber\") = " + je.smembers("number"));
// System.out.println(je.spop("number", 2));
// je.sadd("number2","1","2","3","4","5");
// je.srem("number2","1");//删除集合中的某个数据
System.out.println("je.smembers(\"bnumber2\") = " + je.smembers("number2"));
System.out.println("差集"+je.sdiff("number", "number2"));
System.out.println("交集"+je.sinter("number", "number2"));
System.out.println("并集"+je.sunion("number", "number2"));
System.out.println("个数"+je.scard("number"));
System.out.println("-------------------sort类型--------------------");
// je.zadd("hero",300,"黄忠");
// je.zadd("hero",300,"赵云");
// je.zadd("hero",400,"关羽");
// je.zadd("hero",100,"马超");
System.out.println(je.zrange("hero", 0, -1));//升序打印
System.out.println(je.zrevrange("hero", 0, -1));//降序打印
// je.zincrby("hero",400,"马超");//偏移名称对应的分数,就是加分
System.out.println("je.zrank(\"hero\",\"马超\") = " + je.zrank("hero", "马超"));//排名4升序返回索引
System.out.println("je.zrevrank(\"hero\",\"马超\") = " + je.zrevrank("hero", "马超"));//排名1降序返回索引
System.out.println("个数"+je.zcard("hero"));//返回个数
// 4:关闭资源
je.close();
pool.destroy();
@SpringBootTest
public class RediDemosTest {
@Autowired
private StringRedisTemplate redis;
@Test
public void redistemplates(){
redis.opsForValue().set("name","dagfei");
redis.opsForValue().set("age","12");//设置键值对
System.out.println(redis.opsForValue().increment("age"));//递增
System.out.println(redis.opsForValue().get("name"));//获取key对应的value
System.out.println(redis.opsForValue().decrement("age"));//递减一
System.out.println("-------------------hash类型--------------------");
redis.opsForHash().put("product","奥迪","r8");
redis.opsForHash().put("product","奥迪","q3L");
redis.opsForHash().put("product","奔驰","g20");
System.out.println(redis.opsForHash().get("product", "奥迪"));
System.out.println(redis.opsForHash().hasKey("product","奥迪"));
System.out.println(redis.opsForHash().keys("product"));//获取key对应所有的子元素
System.out.println(redis.opsForHash().delete("product","奥迪"));//删除某一个key的子元素
System.out.println("-------------------list类型--------------------");
redis.opsForList().leftPush("foot","fish","carp");
redis.opsForList().leftPush("foot","fish","crucianCarp");
redis.opsForList().leftPushAll()
redis.opsForValue();//操作字符串
redis.opsForHash();//操作hash
redis.opsForList();//操作list
redis.opsForSet();//操作set
System.out.println("-------------------set类型--------------------");
redis.opsForSet().add("hobby","");//操作set
redis.opsForZSet();//操作有序set
System.out.println("-------------------sort类型--------------------");
redis.opsForList().leftPushAll("hero","黄忠","1","1");
redis.opsForZSet().add("hero","12",2000);//操作有序set
redis.opsForZSet().add("hero","黄忠",2000);//操作有序set
redis.opsForZSet().count("hero",0,-1);//个数
redis.opsForZSet().reverseRange("player",0,-1);
redis.opsForValue().set("hero","赵云");