Redis - 初级一

Redis - 初级一

什么是NoSql

NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ETDyCopv-1606738278586)(images/nosql模型.png)]


NoSQL数据库的由来

​ 随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。


NoSQL数据库的分类

  • 键值存储:这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。Key/value模型对于IT系统来说的优势在于简单、易部署。代表: Redis
  • 列存储数据库:这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。代表: HBase
  • 文档型数据库:文档r型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似。该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。代表: MongoDb
  • 图形数据库:图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。代表: Neo4J

NoSQL数据库的优缺点

优点:

  • 易扩展: NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。
  • 大数据量、高性能: NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。一般MySQL使用 Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用,Cache性能不高。而NoSQL的 Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。
  • 灵活的数据模型: NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的web2.0时代尤其明显。
  • 高可用: NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。

缺点:

但是一些人承认,没有正式的官方支持,万一出了差错会是可怕的,至少很多管理人员是这样看。

“我们确实需要做一些说服工作,但基本在他们看到我们的第一个原型运行良好之后,我们就能够说服他们,这是条正确的道路。”

此外,nosql并未形成一定标准,各种产品层出不穷,内部混乱,各种项目还需时间来检验


什么是Redis

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e0i4qSqX-1606738278596)(\images\redis图.png)]

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。


为什么选用Redis

定位:Redis的定位是缓存,在缓存的方法,Redis的功能更强大

性能极高:读的速度是110000次/s,写的速度是81000次/s。

类型丰富: Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。

原子性 : Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。

丰富的特性: Redis还支持 publish/subscribe(发布/订阅), 通知, key 过期等等特性。

Redis相比memcached有哪些优势?

(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型

(2) redis的速度比memcached快很多

(3) redis可以持久化其数据

(4)Redis支持数据的备份,即master-slave模式的数据备份。

(5) 使用底层模型不同,它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

(6)value大小:redis最大可以达到1GB,而memcache只有1MB


Redis线程之面试题

Redis是单线程还是多线程的?

单线程

Redis 6 之前是单线程

Redis 6 之后引入多线程,但不是真正的多线程,多条线程等待执行,真正执行的只有一条,并不是并行状态,而是并发。


Java操作Redis(基础)

想要自己测试以下代码的话,保证数据库的key不重复!

命令行:flushdb 清空当前数据库,flushall清空所有数据库

Jedis


springboot项目添加依赖

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
@Test
public void testJedisPool() {
    // 1:创建Jedis连接池
    JedisPool pool = new JedisPool("localhost", 6379);
    // 2:从连接池中获取Jedis对象
    Jedis jedis = pool.getResource();
    // 设置密码
 //jedis.auth(密码);
    // 3:操作
		//操作redis
    // 4:关闭资源
    jedis.close();
    pool.destroy();
}

Redis支持5种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。


String类型

redis 最基本的类型,一个 key 对应一个 value。value其实不仅是String,也可以是数字。string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gjS63V1o-1606738278599)(\images\jedis的string类型.jpg)]

应用场景:

  • 常规计数: 微博数, 粉丝数。
  • 共享session:出于负载均衡的考虑,分布式服务会将用户信息的访问均衡到不同服务器上
//空数据库操作
// 存入键值对{age:18}
jedis.set("age", "18");
// 获取指定的key:18
System.out.println(jedis.get("age"));
// 把指定的key对应的值自增
jedis.incr("age");
// 获取指定的key:19
System.out.println(jedis.get("age"));
// 把指定的key对应的值自减
jedis.decr("age");
// 获取指定的key:18
System.out.println(jedis.get("age"));
//空数据库操作
// 存入键值对,如果key存在不做任何操作,否则添加
// 1:操作成功
System.out.println(jedis.setnx("age", "18"));
// 0:操作失败
System.out.println(jedis.setnx("age", "18"));

Hash类型

Redis hash是一个键值(key => value)对集合。Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5x5DE26e-1606738278602)(\images\jedis的hash类型.jpg)]

应用场景:

  • 存储一个用户信息对象数据

注意: redis去模拟关系型复杂查询,开发困难,维护成本高。开发中不建议使用hash, 可以把对象转换成json格式字符串,使用String类型。

//空数据库操作
// 通过map存入
Map<String, String> map = new HashMap<>();
map.put("age", "18");
jedis.hset("user", map);
//存入hash对象
jedis.hset("user", "name", "xiaoming");
// 根据hashKey获取值:xiaoming
System.out.println(jedis.hget("user", "name"));
// 根据hashKey获取值:18
System.out.println(jedis.hget("user", "age"));
// 判断hash对象是否含有指定键:true
System.out.println(jedis.hexists("user", "name"));
// 根据hashKey删除hash对象键值对
jedis.hdel("user", "name", "age");
// 判断hash对象是否含有指定键:false
System.out.println(jedis.hexists("user", "name"));

List类型

Redis list 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nrSjWuXt-1606738278604)(\images\jedis的list类型.jpg)]

应用场景

  • Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。
//空数据库操作
// list集合中元素是有序的
// 往右边添加数据:[a, b]
jedis.rpush("name", "a", "b");
// 往左边添加数据:[d, c, a, b]
jedis.lpush("name", "c", "d");
// 范围显示列表,0 ,-1是显示全部
// [d, c, a, b]
System.out.println(jedis.lrange("name", 0, -1));
// 弹出列表最左边的数据:d
System.out.println(jedis.lpop("name"));
// 弹出列表最右边的数据:b
System.out.println(jedis.rpop("name"));
// 2
System.out.println(jedis.llen("name"));

Set类型

Redis set是string类型的无序集合。集合是通过hashtable实现的,概念和数学中个的集合基本类似,可以交集,并集,差集等等,set中的元素是没有顺序的。所以添加,删除,查找的复杂度都是O(1)。

应用场景:

  • 去重
  • 抽奖(不建议使用)
  • 交集,并集,差集
//空数据库操作
// set集合中元素是无序的
// 往set集合中存储元素
jedis.sadd("name", "a", "b", "c", "d", "e");
// 列出set集合中所有的元素:[b, d, a, c, e]
System.out.println(jedis.smembers("name"));
// 指定删除集合中的元素
jedis.srem("name", "a");
// [b, d , c, e]
System.out.println(jedis.smembers("name"));
// 随机弹出集合中的元素 b
System.out.println(jedis.spop("name"));
// 返回set集合中元素个数:3
System.out.println(jedis.scard("name"));
//空数据库操作
// set集合中元素是无序的
jedis.sadd("name1", "a", "b", "c");
jedis.sadd("name2", "b", "c", "d");
// 差集:返回key1中特有的元素
// [a]
System.out.println(jedis.sdiff("name1", "name2"));
// [d]
System.out.println(jedis.sdiff("name2", "name1"));

// 交集:返回两个set集合的交集
// [b, c]
System.out.println(jedis.sinter("name1", "name2"));

// 并集:返回两个set集合的并集
// [b, d, a, c]
System.out.println(jedis.sunion("name1", "name2"));

ZSet类型

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

应用场景:

  • 排行榜:-- 实时
//空数据库操作
// zset用于排序(对分数排序)
// 存入分数和名称
jedis.zadd("user",18,"age1");
jedis.zadd("user",19,"age2");
jedis.zadd("user",20,"age3");
// 对指定key中的所有数据升序排序:[age1, age2, age3]
System.out.println(jedis.zrange("user", 0, -1));
// 对指定key中的所有数据降序排序:[age3, age2, age1]
System.out.println(jedis.zrevrange("user", 0, -1));
// 对指定key中的列进行分数偏移:21.0
System.out.println(jedis.zincrby("user", 3, "age1"));
// 对指定key中的所有数据升序排序:[age2, age3, age1]
System.out.println(jedis.zrange("user", 0, -1));

// 返回指定列的升序排名:2
System.out.println(jedis.zrank("user", "age1"));
// 返回指定列的降序排名:0
System.out.println(jedis.zrevrank("user", "age1"));

// 返回元素个数:3
System.out.println(jedis.zcard("user"));

集成SpringBoot


Jedis与集成springboot的命令(方法)名大致相同

添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

注入StringRedisTemplate对象

@Autowired
private StringRedisTemplate redisTemplate;

String类型
@Test
public void testRedisTemplateString1() {
    // String类型
    ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
    // 存入键值对{age:18}
    opsForValue.set("age", "18");
    // 获取指定的key:18
    System.out.println(opsForValue.get("age"));
    // 把指定的key对应的值自增
    opsForValue.increment("age");
    // 获取指定的key:19
    System.out.println(opsForValue.get("age"));
    // 把指定的key对应的值自减
    opsForValue.decrement("age");
    // 获取指定的key:18
    System.out.println(opsForValue.get("age"));
}
@Test
public void testRedisTemplateString2() throws InterruptedException {
    // String类型
    ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
    // 存入键值对,设置失效时间为10s,类型是秒
    opsForValue.set("age", "18", 10, TimeUnit.SECONDS);
    // 获取指定的key:18
    System.out.println(opsForValue.get("age"));
    // 线程暂停6s
    Thread.sleep(6000);
    // 查询当前key还剩多少时间过期:4    前面要设置时间类型,不然这里时间不正确
    System.out.println(redisTemplate.getExpire("age"));
    // 再暂停6s
    Thread.sleep(6000);
    // 获取指定的key:null
    System.out.println(opsForValue.get("age"));

}

Hash类型
@Test
public void testRedisTemplateHash1() throws InterruptedException {
    // Hash类型
    HashOperations<String, Object, Object> opsForHash = redisTemplate.opsForHash();
    // 存入hash对象
    opsForHash.put("user", "name", "xiaoming");
    // 根据hashKey获取值:xiaoming
    System.out.println(opsForHash.get("user", "name"));
    // 根据hashKey删除hash对象键值对
    opsForHash.delete("user", "name");
}

List类型
@Test
public void testRedisTemplateList1() throws InterruptedException {
    // List类型
    ListOperations<String, String> opsForList = redisTemplate.opsForList();
    // 往右边添加数据(单个添加):[a]
    opsForList.rightPush("name", "a");
    // 往右边添加数据(单个添加):[a, b]
    opsForList.rightPush("name", "b");
    // 往右边添加数据(单个添加):[d, c, a, b]
    opsForList.leftPushAll("name", "c", "d");
    // 范围显示列表,0 ,-1是显示全部
    // [d, c, a, b]
    opsForList.range("name", 0, -1);
    // 弹出列表最左边的数据:d
    System.out.println(opsForList.leftPop("name"));
    // 弹出列表最右边的数据:b
    System.out.println(opsForList.rightPop("name"));
    // 2
    System.out.println(opsForList.size("name"));
}

Set类型
@Test
public void testRedisTemplateSet1() throws InterruptedException {
    // Set类型
    SetOperations<String, String> opsForSet = redisTemplate.opsForSet();
    // set集合中元素是无序的
    // 往set集合中存储元素
    opsForSet.add("name", "a", "b", "c", "d", "e");
    // 列出set集合中所有的元素:[b, d, a, c, e]
    System.out.println(opsForSet.members("name"));
    // 指定删除集合中的元素
    opsForSet.remove("name", "a");
    // [b, d , c, e]
    System.out.println(opsForSet.members("name"));
    // 随机弹出集合中的元素 c
    System.out.println(opsForSet.pop("name"));
    // 返回set集合中元素个数:3
    opsForSet.size("name");
}

@Test
public void testRedisTemplateSet2() throws InterruptedException {
    // Set类型
    SetOperations<String, String> opsForSet = redisTemplate.opsForSet();
    // set集合中元素是无序的
    opsForSet.add("name1", "a", "b", "c");
    opsForSet.add("name2", "b", "c", "d");
    // 差集:返回key1中特有的元素
    // [a]
    System.out.println(opsForSet.difference("name1", "name2"));
    // [d]
    System.out.println(opsForSet.difference("name2", "name1"));

    // 交集:返回两个set集合的交集
    // [b, c]
    System.out.println(opsForSet.intersect("name1", "name2"));

    // 并集:返回两个set集合的并集
    // [b, d, a, c]
    System.out.println(opsForSet.union("name1", "name2"));
}

ZSet类型
@Test
public void testRedisTemplateZSet1() throws InterruptedException {
    // ZSet类型
    ZSetOperations<String, String> opsForZSet = redisTemplate.opsForZSet();
    // zset用于排序(对分数排序)
    // 存入分数和名称
    opsForZSet.add("user", "age1", 18);
    opsForZSet.add("user", "age2", 19);
    opsForZSet.add("user", "age3", 20);
    // 对指定key中的所有数据升序排序:[age1, age2, age3]
    System.out.println(opsForZSet.range("user", 0, -1));
    // 对指定key中的所有数据降序排序:[age3, age2, age1]
    System.out.println(opsForZSet.reverseRange("user", 0, -1));
    // 对指定key中的列进行分数偏移:18 + 3 -> 21.0
    System.out.println(opsForZSet.incrementScore("user", "age1", 3));
    // 对指定key中的所有数据升序排序:[age2, age3, age1]
    System.out.println(opsForZSet.range("user", 0, -1));

    // 返回指定列的升序排名:2
    System.out.println(opsForZSet.rank("user", "age1"));
    // 返回指定列的降序排名:0
    System.out.println(opsForZSet.reverseRank("user", "age1"));

    // 返回元素个数:3
    System.out.println(opsForZSet.zCard("user"));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值