NoSql数据库—Redis

1.NoSql数据库

1.1 what(什么是NoSQL数据库)

    NoSql全称 not only sql ,非关系型数据库。他采用简单、高效的数据格式(例如key-value等)将数据存储于内存中,极大地提高了数据的访问速度。可以作为关系型数据库的一个很好的补充但不能代替关系型数据库。

1.2 why(为什么要使用NoSQL数据库)

    传统关系型数据库一般用来存储重要信息,应对普通的业务是没有问题的。但是,随着互联网的高速发展,传统的关系型数据库在应付超大规模,超大流量以及高并发的时候力不从心。
    为了解决高并发、高可扩展(集群)、高可用(不能宕机)、大数据存储问题而产生的数据库解决方案,就是NoSql数据库。

1.3 where(应用场景?)

    Nosql数据库相较于传统关系型数据库,最大的优点就是存储简单、访问速度快
    根据它的特点主要有以下几点应用:
        缓存
        分布式集群架构中的session分离
        任务队列(秒杀、抢购、12306等等)
        应用排行榜(SortedSet)
        网站访问统计
        数据过期处理(expire)

1.4 How(如何使用?)

    接下来的整篇文章,都在介绍如何使用。

关系型数据库和非关系数据的比较

存储方式 存储结构 存储规范 存储扩展 查询方式 事务 性能
关系 二维表 结构化数据(预先定义列结构) 存储于表中(避免重复、结构清晰) 纵向扩展(操作的性能瓶颈可能涉及多个表,需要通过提高计算机的性能来克服) 结构化的查询方式(SQL) 支持-遵循ACID规则 低(维护数据的一致性付出了巨大的代价)
非关系 数据集(键值,文档等) 动态结构(适应数据类型、和结构变化) 存储于数据集中(可重复、易读写) 横向扩展(天然分布式) key-value查询(类似map) 支持-遵循BASE原则 高(数据松散且存储于内存中)

常见的关系型数据库

键值(Key-Value)存储数据库
相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB。
典型应用:内容缓存,主要用于处理大量数据的高访问负载。
数据模型:一系列键值对
优势:快速查询
劣势:存储的数据缺少结构化

列存储数据库
相关产品:Cassandra, HBase, Riak
典型应用:分布式的文件系统
数据模型:以列簇式存储,将同一列数据存在一起
优势:查找速度快,可扩展性强,更容易进行分布式扩展
劣势:功能相对局限

文档型数据库
相关产品:CouchDB、MongoDB
典型应用:Web应用(与Key-Value类似,Value是结构化的)
数据模型:一系列键值对
优势:数据结构要求不严格
劣势:查询性能不高,而且缺乏统一的查询语法

图形(Graph)数据库
相关数据库:Neo4J、InfoGrid、Infinite Graph
典型应用:社交网络
数据模型:图结构
优势:利用图结构相关算法。
劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。

2.Reids

2.1 简介

    Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库(nosql),应用在缓存。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型有5种
    如下:
        字符串类型 (String)
        散列类型(hash)
        列表类型(List)
        集合类型(set)
        有序集合类型(SortedSet)

2.2 安装(单机)

1>下载

官网地址:http://redis.io/

2.安装c语言编译环境gcc

 yum -y install gcc-c++

3.上传tar包,解压缩 tar-zxvf 目录
4.进行编译 : cd到解压目录 ,输入命令 make
5.执行安装(指定安装目录)

make install PREFIX=/usr/local/redis	

在这里插入图片描述
6.进入安装目录,查看是有bin目录存在

2.3 服务/客户端的连接、关闭

服务端-前端启动:

		bin目录下: ./redis-server 

在这里插入图片描述
这种启动方式后我们就不能进行其他的操作了, Ctrl+C 即可退出。

服务端-后台启动(推荐):
第一步:把解压目录中的/redis.conf复制到安装目录/usr/local/redis/bin目录下
第二步:使用vim命令修改redis.conf配置文件 将daemonize no修改为daemonize yes
在这里插入图片描述
第三步:输入启动命令 (bin目录下)

	   ./redis-server redis.conf

第四步:检查redis进程

		ps -ef|grep redis

客户端的启动
1> 使用Redis-cli建立连接:

        bin目录下: ./redis-cli 

    默认连接localhost运行在6379端口的redis服务。

		完整命令如下:./redis-cli -h 192.168.25.131 -p 6379

在这里插入图片描述

2>使用redis的桌面程序建立连接
    下载安装Redis-Deskop-manager即可,这里就不演示了。

退出客户端cli 连接
    第一种:
        [root@localhost bin]# ./redis-cli
        127.0.0.1:6379> quit
    第二种:
        [root@localhost bin]# ./redis-cli
        127.0.0.1:6379> exit
    第三种:CTR+C

退出redis服务
    第一种:通过连接上客户端进行关闭,使用shutdown 命令。
在这里插入图片描述
    第二种:使用 kill 命令。
        找到对应的redis的进程id 然后使用命令:(pid为进程id) kill -9 pid

2.4 常用的数据类型

1>String

命令 格式
设置值 set key value
获取值 get key
设置获取值(返回该值的原始值) getset key value
删除数据(通用) del key
递增1 incr key
递增指定长度 incrby key 递增值
递减1 decr key
递增指定长度 decrby key 递增值
追加字符串(返回追加后的长度) append key value
查询所有key(通用) keys *
判断key是否存在(1,0) exits key

在这里插入图片描述

2>Hash

命令 格式
设置值 [多个] hset key field value [field1 value1 field2 valued…]
获取值 hget key field
获取值 [多个] hmget key field [field1 field2…]
获取所有的field value hgetall key
删除指定field hdel key field
删除指定key(通用) del key
递增/减(num的正负) hincr key field num
判断field是否存在 hexits key field
获取key中field的个数 hlen key
获取key中所有的field hkeys key
获取key中所有的value hvalue key

在这里插入图片描述

3>List

List是有顺序可重复(数据结构中的:双链表,队列)
可作为链表 ,从左添加元素  也可以从右添加元素。
命令 格式
插入(左/右) lpush/rpush key value[value1 value2 …]
查看 lrange key start end (start:从0开始,end可以为负数,表示倒数第几个,0 -1表示查看所有)
弹出(删除) lpop/rpop key (从左/右删除,并返回被删除的元素)
获取个数 llen key
添加如果key存在 lpushx/rpushx key value [value1 value2 …]
删除(从哪开始删除几个value) lrem key num value 例如:lrem key 2 1 表示从左边开始删除2个1,若num为0则表示全部删除、num为负数 表示从右开始删除]
插入到指定位置 lset key index value (注意从0开始)

在这里插入图片描述

4>Set

命令 格式
添加 sadd key value1 [value2 value3…]
删除 srem key value1 [value2 value3…]
查看 smembers key
判断是否存在 sismember key value
差级运算 sdiff key1 key2 (key2相对于key1的差, 结果和key1、key2顺序有关)
交集运算 sinter key1 key2
并集运算 sunion key1 key2
得到元素的数量 scard key
随机返回指定数量成员 srandmember key [count] (不写count默认返回一个)
设置新集合保存差值、并集、交集 sdiffstore/sinterstore/sunionstore key key1 key2

在这里插入图片描述

5>ZSet

有顺序,不能重复,如果重复会覆盖,适合做排行榜
命令 格式
添加 zadd key 分数1 值1 分数2 值2 …
获取分数 zscore key value
获取value的数量 zcard key
范围查找 zrange/zrevrange key start end [withscores] (分数可选择是否显示,range从小到大,rerange 从大到小)
删除 zrem key value1 [value2 value3 …]
按照排名的顺序删除 zremrangebyrank key start end
按照分数范围删除 zremrangebyscore key 分数1 分数2
统计分数之间的value个数 zcount key 分数1 分数2 (注意分数1>=分数2)
添加分数 zincrby key 分数 value

2.5通用操作

命令 格式
获取所有的key keys *
判断key是否存在 exists key
key重命名 rename old new
删除key del key [key1 key2 …]
设置key的过期时间 expire key time (time : 0 负数,可以理解为立刻删除)
查看当前key所剩时间 ttl key (-1表示永久,-2表示不存在)
持久化key persist key (ttl查看时间为-1)
查看当前key的类别 type key
清空当前库 full all

2.7Reids特性

1>多数据库

Redis中共有16个数据库,索引从0开始,默认是选择第0个
        切换数据库: select index[0-15]
        移动到某库:move key index

2>事务机制

    相比于传统的关系型数据库来说,Redis的事务并不突出,所以了解即可。
        开启:multi
        提交:exec
        回滚:discard

3>Redis持久化

    Redis的高性能源于其数据保存于内存中,所以存取都是相当快,但是当断电时,内存中的数据便会丢失,此时我们需要将数据持久化 内存->硬盘,下次启动的时候,redis会依据持久化的信息做数据恢复。

1.RDB   快照形式  (定期将当前时刻的数据保存磁盘中)会产生一个dump.rdb文件
	特点:会存在数据丢失,性能较好,数据备份。
2.AOF   append only file ,日志形式 (所有对redis的操作命令记录在aof文件中),恢复数据,重新执行一遍即可。
	特点:每秒保存,数据比较完整,耗费性能。	

RDB:快照模式默认开启,默认会将dump.rdb文件保存在redis安装目录根目录下。
     优点:
        1.只包含一个文件
        2.性能最大化
    缺点:
        1.指定间隔保存,宕机时总有来不及保存的文件。
        2.如果指定间隔时间过长,保存的停顿时间很大(Reids是单线程的)

在redis.conf中配置RDB的保存时间间隔:
在这里插入图片描述
AOF:是采取日志记录的方式、可以每秒,每次修改,进行数据持久化。
     优势:
          1.数据安全性高,数据丢失概率小。
          2.采用追加写入,日志过大,自动重写(瘦身)
          3.格式清晰,易于修改日志文件
     劣势:
        文件大,持久化次数频繁、运行效率低于RDB
修改redis.conf 配置文件,开启AOF
在这里插入图片描述
主要是修改:
     1.开启aof appendobly yes
     2.appendsync 选中同步策略, always或者eyerysec
     修改后需要停掉redis,重启服务。

注意:默认使用rdb方式,但是如果两都开启了,会使用aof

3.Jedis

Jedis即:Redis的Java客户端API,使用方式也很简单

			<!-- Redis客户端 -->
			<dependency>
				<groupId>redis.clients</groupId>
				<artifactId>jedis</artifactId>
				<version>xxxxxxx</version>
			</dependency>

3.1常用API

	// string类型操作
	@Test
	public void string_test() {
		// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
		// 添加设置字符串
		jedis.set("hello", "word");
		String result = jedis.get("hello");
		System.out.println(result); // world
		// 添加数字,自增长
		jedis.set("id", "1");
		String id = jedis.get("id");
		System.out.println(id); // 1
		System.out.println(jedis.incr("id")); // 2
		System.out.println(jedis.get("id")); // 2
		// 第三步:关闭Jedis
		jedis.close();
	}
     
     //hash类型的操作
	@Test
	public void hash_test() {
		// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
		// 添加map的redis的hash中
		Map<String, String> map = new HashMap<>();
		map.put("name", "faker");
		map.put("grade", "100");
		jedis.hmset("skt", map);
		// 获取指定field值
		System.out.println(jedis.hget("skt", "name")); // faker
		// 获取个field对应的值
		jedis.hmget("skt", "name", "grade").forEach(System.out::println); // faker 100
		// 设置增长
		System.out.println(jedis.hincrBy("skt", "grade", 20)); // 120
		jedis.close();
	}
    
    // list类型的操作
	@Test
	public void list_test() {
		// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
		// 分别从左右添加
		jedis.lpush("list", "1", "2", "3");
		jedis.rpush("list", "x", "y", "z");
		// lrange 获取指定范围的值
		jedis.lrange("list", 0, -1).forEach(System.out::println); // 3 2 1 x y z
		// pop 弹出,删除指定值
		System.out.println(jedis.rpop("list")); // z
		// lset 在指定位设置指定值
		jedis.lset("list", 0, "first");
		jedis.lrange("list", 0, -1).forEach(System.out::println); // first 2 1 x y
		jedis.close();
	}
	
	// set类型的操作
	@Test
	public void set_test() {
		// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
		// sadd添加值
		jedis.sadd("set", "1", "faker", "2");
		// smembers获取所有值
		jedis.smembers("set").forEach(System.out::println); // 2 faker 1
		// srem 删除指定value
		jedis.srem("set", "1");
		// sismember判断指定vlaue是否存在
		System.out.println(jedis.sismember("set", "1")); // false
		jedis.close();
	}
	
	// zset类型的操作
	@Test
	public void zset_add() {
		// 第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
		Jedis jedis = new Jedis("192.168.25.131", 6379);
		// 第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
		Map<String, Double> zset = new HashMap<>();
		zset.put("faker", 100d);
		zset.put("clearlove", 99d);
		zset.put("uzi", 99d);
		// 向zset中插入数据
		jedis.zadd("zset", zset);
		// 获取zset中的所有数据
		Set<Tuple> withScores = jedis.zrangeWithScores("zset", 0, -1);
		withScores.forEach(e -> {
			System.out.println(e.getElement() + "-------" + e.getScore());
			// clearlove-------99.0 uzi-------99.0 faker-------100.0
		});
		// 获取指定value的分数
		System.out.println(jedis.zscore("zset", "faker")); // 100.0
		jedis.close();
	}

    通过上述代码可以看出,使用Jedis操作Reids首先要获取连接对象(Jedis),这和传统的数据库获取connection对象是一样的,Jedis也为我们提供了连接池的方式,在程序中更推荐大家使用连接池方式。

	@Test
	public void testJedisPool() throws Exception {
		// 第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。
		JedisPool jedisPool = new JedisPool("192.168.25.131", 6379);
		// 第二步:从JedisPool中获得Jedis对象。
		Jedis jedis = jedisPool.getResource();
		// 第三步:使用Jedis操作redis服务器。
		jedis.set("jedis", "test");
		String result = jedis.get("jedis");
		System.out.println(result); //jedispool
		// 第四步:操作完毕后关闭jedis对象,连接池回收资源。
		jedis.close();
		// 第五步:关闭JedisPool对象。
		jedisPool.close();
	}

3.2 Spring整合Redis

Redis和Spring的整合十分的简单,我们只需要使用Spring容器管理JedisPool就可以了

1.首先加入相关的spring、jedis依赖

        <!--此处为了方便直接引入springmvc的配置文件-->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.3.16.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>

2.配置

	<!-- 配置redis连接池 -->
	<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
		<constructor-arg name="host" value="192.168.25.131"></constructor-arg>
		<constructor-arg name="port" value="6379"></constructor-arg>
	</bean>

3.测试

@Test
	public void redis_spring_test() {
		// 1.首先加载spring的配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		// 2.获取连接池对象
		JedisPool pool = applicationContext.getBean(JedisPool.class);
		// 3.获取Jedis对象
		Jedis jedis = pool.getResource();
		jedis.set("hello", "world");
		System.out.println(jedis.get("hello")); // world
		jedis.close();
		pool.close();
	}

发布了5 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_37328871/article/details/84575229