NoSql数据库--Redis入门

Redis入门

1、NoSQL概述【重点了解】

1.1 什么是NoSQL

​ NoSQL(NoSQL=Not Only SQL),意即"不仅仅是SQL"是一项全新的数据库理念,泛指非关系型数据库。

【关系型数据库】
	关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织
优点:
	1、易于维护:都是使用表结构,格式一致;
	2、使用方便:SQL语言通用,可用于复杂查询;
	3、复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。
缺点:
	1、读写性能比较差,尤其是海量数据的高效率读写;
	2、固定的表结构,灵活度稍欠;
	3、高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。//     35万/s

【非关系型数据库】
	非关系型数据库严格上讲不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
优点:
	1、格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
	2、速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘;
	3、高扩展性;
	4、成本低:nosql数据库部署简单,基本都是开源软件。
缺点:
	1、不提供sql支持,学习和使用成本较高;
	2、无事务处理;
	3、数据结构相对复杂,复杂查询方面稍欠

1.2 为什么要用NoSQL

​ 随着互联网的高速崛起,网站的用户群的增加,访问量的上升,传统数据库上都开始出现了性能瓶颈,web程序不再仅仅专注在功能上,同时也在追求性能。所以NOSQL数据库应运而上,具体表现为对如下三高问题的解决:

【High performance 】- 对数据库高并发读写的需求 
	web2.0网站要根据用户个性化信息来实时生成动态页面和提供动态信息,所以基本上无法使用动态页面静态化技术,因此数据库并发负载非常高,往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。其实对于普通的BBS网站,往往也存在对高并发写请求的需求,例如网站的实时统计在线用户状态,记录热门帖子的点击次数,投票计数等,因此这是一个相当普遍的需求。

【Huge Storage 】- 对海量数据的高效率存储和访问的需求 
	类似Facebook,twitter,Friendfeed这样的SNS网站,每天用户产生海量的用户动态,以Friendfeed为例,一个月就达到了2.5亿条用户动态,对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的。再例如大型web网站的用户登录系统,例如腾讯,盛大,动辄数以亿计的帐号,关系数据库也很难应付。 

【High Scalability && High Availability】- 对数据库的高可扩展性和高可用性的需求 
	在基于web的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移。

1.3 主流的NoSQL产品

在这里插入图片描述

【NoSQL数据库分类】

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

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


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

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

1.4 NoSQL的特点

​ NoSQL数据库在大数据存储上具有关系型数据库无法比拟的优势:

1、易扩展
	NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。

2、大数据量,高性能
	NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。

3、灵活的数据模型
	NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。这点在大数据量的Web2.0时代尤其明显。

4、高可用
	NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如Cassandra,HBase模型,通过复制模型也能实现高可用。

​ 综上所述,NoSQL的非关系特性时期成为了后web2.0时代的宠儿,助力大型的web2.0网站的再次起飞,是一项全新的数据库革命性运动。

​ web1.0—传播信息(静态网页)

​ web2.0—微博(交互性)-- 功能实现,用户体验(性能–NoSQL)

2、Redis概述

2.1 Redis的由来

	2008年,意大利的一家创业公司Merzia推出了一款基于MySQL的网站实时统计系统LLOOGG,然而没过多久该公司的创始人Salvatore Sanfilippo便对MySQL的性能感到失望,于是他决定亲自为LLOOGG量身订做一个数据库,并于2009年开发完成,这个数据库就是Redis。不过Salvatore Sanfilippo并不满足只将Redis用于LLOOGG这一款产品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo将Redis开源发布,并开始和Redis的另一名主要的代码贡献者Pieter Moordhuis一起继续着Redis的开发,今天。
	
	Salvatore Sanfilippo自己也没想到,短短的几年时间,Redis就拥有了庞大的用户群体。Hacker News在2012年发布了一份数据库的使用情况调查,结果显示有近12%的公司在使用Redis。国内如新浪微博,街旁网,知乎网,国外如GitHub,Stack Overflow,Flickr等都是Redis的用户。
	
	VMware公司从2010年开始赞助Redis的开发,Salvatore Sanfilippo和Pieter Noordhuis也分别在3月和5月加入VMware,全职开发Redis。

2.2 什么是Redis

​ Redis是用C语言开发的一个开源的高性能键值对(Key-Value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的值数据类型如下:

1. 字符串类型 	  string(常用:json/xml)
2. 散列类型   	   hash(key--value)map
3. 列表类型		   list	linkedlist 用户列表
4. 集合类型		   set
5. 有序集合类型	 sortedset
Redis: 软件--C语言--存储数据
特点:key-value ,内存存储

2.3 Redis的应用场景

​ Redis在很多方面与其他数据库解决方案不同:它使用内存提供主存储支持,而仅使用硬盘做持久性的存储;在一些需要大容量数据集的应用,Redis并不适合,因为它的数据集不会超过系统可用的内存。我们通常把它融入到系统中来,这就能够解决很多问题,比如那些你现有的数据库处理起来感到缓慢的任务。这些你就可以通过Redis来进行优化,或者为应用创建些新的功能。

1、缓存(数据查询,端链接,新闻内容,商品内容等等);--使用最多
2、聊天室的在线好友列表;
3、任务队列;(秒杀,抢购,12306等等)
4、应用排行榜;
5、网站访问统计;
6、数据过期处理(可以精确到毫秒);
7、分布式集群架构中的session分离;

3、window版Redis的安装与使用

3.1 window版Redis下载

​ 官方提倡使用Linux版的Redis,所以官网只提供了Linux版的Redis下载,我们可以从GitHub上下载window版的Redis,具体链接地址如下:

官网下载地址:		http://redis.io/download
github下载地址:	  https://github.com/MSOpenTech/redis/tags

在这里插入图片描述

3.2 window版Redis的目录结构

​ 将上述压缩包解压后得到如下目录:
在这里插入图片描述
【Redis目录介绍】

目录或文件作用
redis-benchmark性能测试工具
redis-check-aofAOF文件修复工具
redis-check-dumpRDB文件检查工具(快照持久化文件)
redis-cli命令行客户端
redis-serverredis服务器启动命令
redis.windows.confredis核心配置文件

3.3 window版Redis的安装

​ window版的Redis是免安装的,将压缩包解压完成即可使用。

3.4 window版Redis的启动与关闭

启动:双击redis-server.exe
关闭:Ctrl+C 或者 将服务窗口关闭

在这里插入图片描述

3.5 连接Redis服务

​ Redis数据库服务的连接有两种方式:

  1. 命令行工具:
  2. 图形化界面工具:
【命令行工具使用】

​ 双击redis-cli.exe文件,会弹出命令行客户端窗口,我们可以在这个窗口中书写redis的命令:ping 。如果服务器能够返回PONG说明,连接成功!

在这里插入图片描述

【图形化界面工具】

​ 开发中,我们往往会使用图形化界面工具连接Redis服务,对Redis中的数据进行更加直观地操作。图形化界面工具是一个独立的软件,使用之前需要先进行安装。软件在资料中:
在这里插入图片描述
【使用步骤】

  1. 安装:双击,下一步即可完成安装;

  2. 连接:新建连接,配置连接信息;
    在这里插入图片描述

  3. 查看Redis实例:双击刚刚创建的连接,如果出现16个db实例,即说明连接成功。

在这里插入图片描述

【注意】

  1. redis服务器中默认的数据库数量是16,如果不指定数据库,默认使用id为0的数据库;
  2. 切换数据库的命令:SELECT ;

4、Redis的数据结构

​ Redis是一种高级的Key-Value类型的存储系统,其中key值是字符串类型,value值支持5种常用的数据类型。

redis中文网:http://www.redis.net.cn/order/

4.1 Redis中的Key值

​ Redis中的key值是字符串类型,key值是Redis中数据查询和存储的依据。我们在往Redis中存储数据时,关于key值的命名需要注意以下几点:

key不要太长,最好不要超过1024个字节,这不仅会消耗内存还会降低查找效率
key不要太短,如果太短会降低key的可读性 
key命名规范,在项目中key最好有一个统一的命名规范

4.2 Redis中的Value值

​ Redis中的Value值是用来存储具体数据的,常用的数据类型有以下5种:

· 字符串(String)
· 哈希(hash)
· 字符串列表(list)
· 字符串集合(set)
· 有序字符串集合(sorted set)

​ 在日常开发中主要使用比较多的有字符串、哈希、字符串列表、字符串集合四种类型,其中最为常用的是字符串类型。

4.3 字符串类型(String)

应用场景:

常规key-value缓存应用。常规计数: 微博数, 粉丝数,json格式的数据。
1. 字符串类型string概述
	字符串类型是Redis中最为基础的数据存储类型,字符串在Redis中是二进制保存,因此是安全的,这便意味着该类型存入和获取的数据相同。
	在Redis中字符串类型的Value最多可以容纳的数据长度是512M。
2. 字符串类型string常用命令
功能命令说明
设置(修改)值set key value该key存在则进行覆盖操作,该操作总是返回"OK"。
获取值get key获取该key关联的字符串value值。如果value值不是字符串
会报错,如果key不存在则返回nil。
删除数据del key [key2 key3…]根据指定的key删除对应的数据。可一次删除多个
批量设置值mset key1 value1 key2 value2同时设置多对键值对
批量取值mget key1 key2同时获取过个key值对应的value值
设置值(返回原来的值)getset key value给指定的key设置value值,返回原来的值(如果原来没有值返回nil)

注:查看redis中的所有key值: keys *

【命令】set key value

​ 设定key持有指定的字符串value,如果该key存在则进行覆盖操作。总是返回”OK”。

​ 注意:value值可以可以不用添加双引号。value值在redis中都是以字符串的形式进行存储;

127.0.0.1:6379> set name "zhangsan"
OK
127.0.0.1:6379> set addr shanghai
OK
127.0.0.1:6379> set age 13
OK

【命令】get key

​ 获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息,因为get命令只能用于获取String value;如果该key不存在,返回(nil)。

127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> get addr
"shanghai"
127.0.0.1:6379> get age
"13"
127.0.0.1:6379> get company
(nil)

【命令】del key

​ 根据指定的key删除对应的数据。

127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> del name
(integer) 0

【扩展】

  1. 设置多个值:mset key1 value1 [key2 value2 …]
127.0.0.1:6379> mset name zhangsan age 13
OK
  1. 获取多个值:mget key1 [key2…]
127.0.0.1:6379> mget name age
1) "zhangsan"
2) "13"
  1. 设置值(返回原值):getset key value
127.0.0.1:6379> getset name lisi
"zhangsan"
127.0.0.1:6379>

4.4 Hash类型数据

4.4.1 Hash类型数据概述

​ Redis中的Hash类型可以看成具有String Key和String Value的map容器。所以该类型非常适合于存储值对象的信息。如username、password和age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储4294967295个键值对。
在这里插入图片描述

	Key是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 
	也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。
4.4.2. 哈希类型hash常用命令

使用场景:

	存储部分变更数据,如用户信息等。 

常用命令

功能命令说明
为指定的key设定field/valuehset key field value设置单个值
获取指定key的field对应的value值hget key field获取单个值
删除指定key的field对应的value值hdel key field [field2 …]可以删除多个值
为指定的key批量设置值hmset key field value [field2 value2]批量设置值
获取指定key的多个值hmget key field[field2 field3 …]批量获取值
获取指定key的所有键值对hgetall key获取所有的键值对

【命令】 : **hset key field value **

​ 为指定的key设定field/value对(键值对)。

127.0.0.1:6379> hset stu name zhangsan
(integer) 1
127.0.0.1:6379>

【命令】 hget key field

​ 返回指定的key中的field的值

127.0.0.1:6379> hget stu name
"zhangsan"
127.0.0.1:6379>

【命令】 hmset key field value[field2 value2 …]

​ 批量给指定key设置多个key-value值

127.0.0.1:6379> hmset stu name zhangsan age 13
OK
127.0.0.1:6379>

【命令】 hmget key field[field2 …]

​ 批量获取指定key的多个key-value值

127.0.0.1:6379> hmget stu name age
1) "zhangsan"
2) "13"
127.0.0.1:6379>

【命令】 **hgetall key **

​ 批量获取指定key的所有key-value值

127.0.0.1:6379> hgetall stu
1) "name"
2) "zhangsan"
3) "age"
4) "13"
127.0.0.1:6379>

【命令】 hdel key field [field2 … ]

​ 可以删除一个或多个字段,返回值是被删除的字段个数

127.0.0.1:6379> hdel stu name age
(integer) 2
127.0.0.1:6379>

4.5 列表类型list

应用场景:

list集合: 存取有序(存入时的顺序),有索引,可以重复 ------- 查询快,增删慢

	Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。
	List 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用List结构,我们可以轻松地实现最新消息排行等功能。List的另一个应用就是消息队列,可以利用List的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作List中某一段的api,你可以直接查询,删除List中某一段的元素。
4.5.1. 列表类型list概述

在这里插入图片描述

	在Redis中,List类型是按照插入顺序排序的字符串链表,可保存重复数据。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。
	在插入时,如果该键不存在,Redis将为该键创建一个新的链表。
	如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。
	List中可以包含的最大元素数量是4294967295
4.5.2 列表类型list常用命令
功能命令说明
头部插入数据lpush key value1 value2…从list的头部开始插入数据
尾部插入数据rpush key value1 value2…从list的尾部开始插入数据
查看list中所有数据lrange key 0 -1索引0指的是列表中第一个元素,-1指列表中最后一个元素
查看list中指定索引区间的元素lrange key start endstart:开始索引,从0开始;end:结束索引;
查看指定索引的值lindex key indexindex:值在list中的索引
从list的头部弹出一个值lpop key获取并移除list头部的第一个值
从list的尾部弹出一个值rpop key获取并移除list头部的最后一个值

【命令-头部插入】 lpush key value1 value2 …

	在指定的key所关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据。如果插入成功,返回元素的个数。
127.0.0.1:6379> lpush stus zhagnsan lisi wangwu
(integer) 3
127.0.0.1:6379>

在这里插入图片描述
在这里插入图片描述

【命令-尾部插入】 rpush key value value value

	在指定的key对应的list的尾部插入所有的value,如果该key不存在,该命令在插入之前创建一个与该key对应的空链表,再从尾部插入数据。如果插入成功,返回元素的个数。
127.0.0.1:6379> rpush strs zhangfei guanyu liubei
(integer) 3
127.0.0.1:6379>

在这里插入图片描述
在这里插入图片描述

【命令-查看列表】 lrange key 0 -1lrange key start end

​ 查看list中的所有数据;

127.0.0.1:6379> lrange stus 0 -1
1) "wangwu"
2) "lisi"
3) "zhagnsan"
127.0.0.1:6379>

​ 查看list中索引为start到end的数据;

127.0.0.1:6379> lrange stus 0 2
1) "wangwu"
2) "lisi"
3) "zhagnsan"
127.0.0.1:6379>

【命令-从list头部取出元素】 lpop key

返回并弹出指定的key关联的链表中的第一个元素,即头部元素。

如果该key不存在,返回nil;

若key存在,则返回链表的头部元素。

127.0.0.1:6379> lpop stus
"wangwu"
127.0.0.1:6379>

在这里插入图片描述
【命令-从list尾部取出元素】rpop key

从尾部弹出元素。

127.0.0.1:6379> rpop stus
"zhagnsan"
127.0.0.1:6379>

5.6 集合类型set

set集合: 存取无序 ,不重复 --增删快,查询慢

应用场景:

   Redis set对外提供的功能与list类似是一个列表的功能, 特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。
5.6.1 集合类型set

​ 在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。需要说明的是,这些操作的时间复杂度为O(1),即常量时间内完成次操作。Set可包含的最大元素数量是4294967295。

​ 和List类型不同的是,Set集合中不允许出现重复的元素。

5.6.2 集合类型set的常用命令
功能命令说明
设置值sadd key value [value1,value2…]
查看set中的所有值smembers key
移除并返回集合中的任意一个元素spop key
删除值【set集合中是元素删除完后set消失】srem key members[member1、member2…]
获取集合中的成员数scard key

【命令-设置值】sadd key values[value1,value2…]

​ 向set中添加数据,如果该key的值已有则不会重复添加

127.0.0.1:6379> sadd myset zhagnsan lisi wangwu
(integer) 3
127.0.0.1:6379>

【命令-获取值】smembers key

​ 获取set中所有的成员

127.0.0.1:6379> smembers myset
1) "wangwu"
2) "lisi"
3) "zhagnsan"
127.0.0.1:6379>

【命令-删除值】 srem key members[member1、member2…]

​ 删除set中指定的成员

127.0.0.1:6379> srem myset wangwu lisi
(integer) 2
127.0.0.1:6379> smembers myset
1) "zhagnsan"
127.0.0.1:6379>

5.7 有序集合 sorted set

5.7.1 有序集合sorted set应用场景
	Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。它用来保存需要排序的数据。例如排行榜,一个班的语文成绩,一个公司的员工工资,一个论坛的帖子等。有序集合中,每个元素都带有score(权重),以此来对元素进行排序。它有三个元素:key、member和score。以语文成绩为例,key是考试名称(期中考试、期末考试等),member是学生名字,score是成绩。

有序集合有两大基本用途:排序和聚合
5.7.2 sorted set的常用命令
功能命令说明
添加一个或多个成员zadd key score1 member1[score2 member2 …]
获取有序集合的成员数zcard key
通过索引区间返回有序集合成指定区间内的成员zrange key start stop [withscores]
通过索引区间返回有序集合成指定区间内的成员【顺序排列】zrange key start stop withscores
通过索引区间返回有序集合成指定区间内的成员【倒序排列】zrevrange key start stop withscores
移除有序集合中的一个或多个成员zrem key member[member1 … ]

【命令-设置值】zadd key score member[score1 member1,score2 member2…]

​ 往有序集合中添加元素: score member

127.0.0.1:6379> zadd scores 60 chinese 100 english 80 math
(integer) 3
127.0.0.1:6379>

在这里插入图片描述

【命令-获取集合成员数】zcard key

127.0.0.1:6379> zcard scores
(integer) 3
127.0.0.1:6379>

【命令-查询集合中的元素】zrange key start stop [withscores]

​ 注:zrange key 0 -1 是查询所有元素;

127.0.0.1:6379> zrange scores 0 2
1) "chinese"
2) "math"
3) "english"
127.0.0.1:6379> zrange scores 0 2 withscores
1) "chinese"
2) "60"
3) "math"
4) "80"
5) "english"
6) "100"
127.0.0.1:6379> zrange scores 0 -1
1) "chinese"
2) "math"
3) "english"
127.0.0.1:6379>

【命令-删除集合中的元素】 zrem key member[member1 … ]

127.0.0.1:6379> zrem scores math english
(integer) 2
127.0.0.1:6379> zrange scores 0 -1
1) "chinese"
127.0.0.1:6379>

5. Redis的通用命令

【查询key】 keys pattern

获取所有与pattern匹配的key,返回所有与该key匹配的keys。*表示任意一个或多个字符,?表示任意一个字符

127.0.0.1:6379> keys *
1) "stu"
2) "strs"
3) "mylist"
4) "scores"
5) "cityData"
6) "stus"
7) "myset"
8) "name"
127.0.0.1:6379> keys name
1) "name"
127.0.0.1:6379>

【根据key值删除】del key1 key2…

​ 删除指定key值的数据

127.0.0.1:6379> del company
(integer) 1

【判断key值是否存在】exists key

判断该key是否存在,1代表存在,0代表不存在

127.0.0.1:6379> exists compnay
(integer) 0
127.0.0.1:6379> exists mylist
(integer) 1
127.0.0.1:6379>

【获取指定key的数据类型】type key

​ 获取指定key的类型。该命令将以字符串的格式返回。 返回的字符串为string、list、set、hash,如果key不存在返回none

127.0.0.1:6379> type name
string
127.0.0.1:6379> type strs
list
127.0.0.1:6379> type stu
hash
127.0.0.1:6379> type myset
set
127.0.0.1:6379> type scores
zset

http://www.redis.net.cn/order/

6. Jedis的基本使用

6.1. jedis的介绍

​ jedis是官方首选的java客户端开发包。

	Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。 
	在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。 
	在企业中用的最多的就是Jedis,Jedis同样也是托管在github上,
	地址:https://github.com/xetorthio/jedis。
	下载jedis解压后得到jar包如下:java操作redis数据库API(Jedis)

6.2. jedis的基本操作

6.2.1. jedis常用API
方法解释
new Jedis(host, port)创建jedis对象,参数host是redis服务器地址,参数port是redis服务端口
set(key,value)设置字符串类型的数据
get(key)获得字符串类型的数据
hset(key,field,value)设置哈希类型的数据
hget(key,field)获得哈希类型的数据
lpush(key,values)设置列表类型的数据
lpop(key)列表左面弹栈
rpop(key)列表右面弹栈
del(key)删除指定的key
6.2.2. jedis的基本操作

导入开发包:

在这里插入图片描述

package com.heima.jedis;

import redis.clients.jedis.Jedis;

public class JedisTest {
    public static void main(String[] args) {
        //1.创建redis核心对象:arg1-host      arg2-端口
        Jedis jedis = new Jedis("localhost",6379);

        //2.存值
        jedis.set("name","黑马程序员");

        //3.取值
        String name = jedis.get("name");
        System.out.println(name);

        //4.释放资源
        jedis.close();
    }
}

7.3. jedis连接池的使用

7.3.1. jedis连接池的基本概念
	jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术--jedisPool。
	jedisPool在创建时初始化一些连接资源存储到连接池中,使用jedis连接资源时不需要创建。
	而是从连接池中获取一个资源进行redis的操作,使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用。
7.3.2. jedisPool的基本使用
package com.heima.jedis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolTest {
    public static void main(String[] args) {
        //1 获得连接池配置对象,设置配置项
        JedisPoolConfig config = new JedisPoolConfig();
        // 1.1 最大连接数
        config.setMaxTotal(30);
        // 1.2  最大空闲连接数
        config.setMaxIdle(10);
        //2 获得连接池
        JedisPool jedisPool = new JedisPool(config, "localhost", 6379);
        //3 获得核心对象
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //4 设置数据
            jedis.set("name", "itcast");
            //5 获得数据
            String name = jedis.get("name");
            System.out.println(name);
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            if(jedis != null){
                jedis.close();
            }
            // 虚拟机关闭时,释放pool资源
            if(jedisPool != null){
                jedisPool.close();
            }
        }
    }
}
7.4. 案例-编写jedis连接池工具类

JedisUtils.java

package com.heima.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ResourceBundle;

/**
 * Jedis工具类
 */
public class JedisUtil {
    private static JedisPool jedisPool;
    private static int maxtotal;
    private static int maxwaitmillis;
    private static String host;
    private static int port;

    //加载配置文件
    static {
        ResourceBundle jedisPorperties = ResourceBundle.getBundle("jedis");
        maxtotal = Integer.valueOf(jedisPorperties.getString("maxtotal"));
        maxwaitmillis = Integer.valueOf(jedisPorperties.getString("maxwaitmillis"));
        port = Integer.valueOf(jedisPorperties.getString("port"));
        host = jedisPorperties.getString("host");
    }


    //初始化连接池
    static {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxtotal);
        config.setMaxIdle(maxwaitmillis);
        jedisPool = new JedisPool(config,host, port);
    }


    /**
     * 获取jedis客户端操作对象
     * @return
     */
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 释放资源
     * @param jedis
     */
    public static void close(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }

}

jedis.properties(src目录下配置文件,编写配置文件)

maxtotal=100
maxwaitmillis=3000
host=127.0.0.1
port=6379

如何快速读取properties配置文件信息

使用jdk提供 ResourceBundle加载 通过getBundle(“文件名”) 通过 getString(“key”)获取目标数据

src下添加Properties配置文件
在这里插入图片描述
内容:

username=lisi
password=123
url=http://xxx
driverclass=com.mysql.jdbc.Driver

加载代码实现 : ResourceBundle.java使用说明

package cn.itheima.jedis.demo;

import java.util.ResourceBundle;

public class PropertiesDemo {
    //  java  专属类   ResourceBundle 对象  jdk 提供
    public static void main(String[] args) {
    //getBundle源码查询 src路路径下的properties文件 传递文件名默认  .properties 所有不需要写扩展名
        String s = ResourceBundle.getBundle("db").getString("driverclass");
        String url = ResourceBundle.getBundle("db").getString("url");
        String aa = ResourceBundle.getBundle("db").getString("username");
        String bb = ResourceBundle.getBundle("db").getString("password");
        System.out.println(s);
        System.out.println(url);
        System.out.println(aa);
        System.out.println(bb);
    }
}

7.案例:Redis实战之查询所有学生

1、需求

​ index.html页面加载完成之后,使用ajax请求将所有的学员信息加载到页面的table中;

2、需求分析

​ 实现如上需求有两种方案,分别如下:

  1. 页面加载完成之后,ajax发送异步请求从数据库查询数据,以后每次请求都从数据库中查询;

  2. 页面加载完成之后,ajax发送异步请求从数据库中查询数据后返回,并把数据存储在redis中,以后的查询直接从redis中获取;

    由于,学生的信息在很长一段时间内是固定不变的,且数据量比较大。如果每次查询都从数据库查询,比较消消耗数据库性能,而且查询速度不快。所以,最佳方案是将数据查询出来后存储在redis中,后面的查询直接从redis中获取。

3、实现步骤

在这里插入图片描述

1、index.html页面加载完成之后,使用ajax技术向后台发送请求查询数据;
2、第一次查询时,直接从数据库中查询,查询到数据后将数据存储在redis中;
3、再次加载index.html页面时,请求发送到后台时,先判断redis中是否有数据,如果有则直接返回;如果没有,从数据库中查询;
4、index.html中拿到数据后,解析数据,将数据插入到页面的table中;

4、代码实现

1、前端页面:

【index.html】

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="css/bootstrap.css">
</head>
<body>
<br><br><br><br><br>
<div class="text-center">
    <a href="stus.html" class="btn btn-primary">学生列表</a>
</div>
</body>
</html>

【stu_list.html】

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>layui</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="css/bootstrap.css">
    <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
    <style>
        .stuTable{
            width: 70%;
            margin: 20px auto;
        }
    </style>
</head>
<body>
<table class="stuTable table table-bordered " id="stuTable" >
    <caption class="text-center h2">学员列表</caption>
    <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>学号</th>
        <th>性别</th>
        <th>班级</th>
        <th>学科</th>
    </tr>
</table>

<script src="js/jquery-3.3.1.js" charset="utf-8"></script>
</body>
</html>
2、后台环境搭建
2.1 数据库
【创建数据库】
CREATE TABLE `stu_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `student_name` varchar(255) DEFAULT NULL,
  `student_no` varchar(255) DEFAULT NULL,
  `sex` int(11) DEFAULT NULL COMMENT '1-男  2-女',
  `class_id` int(11) DEFAULT NULL,
  `test_id` int(11) DEFAULT NULL,
  `subject_no` int(11) DEFAULT NULL COMMENT '学科编号:1-java  2-php 3-python 4-UI 5-前端 6-其他',
  `password` varchar(255) DEFAULT NULL,
  `test_status` int(11) DEFAULT NULL COMMENT '考试状态:0-结束  1-未结束',
  `test_type` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7969 DEFAULT CHARSET=utf8;
【导入数据】

在这里插入图片描述
在这里插入图片描述

2.2 创建实体类Student.java
package com.heima.domain;
public class Student {
    private Integer id;
    private String student_name;
    private String student_no;
    private Integer sex;
    private Integer class_id;
    private Integer subject_no;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getStudent_name() {
        return student_name;
    }

    public void setStudent_name(String student_name) {
        this.student_name = student_name;
    }

    public String getStudent_no() {
        return student_no;
    }

    public void setStudent_no(String student_no) {
        this.student_no = student_no;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public Integer getClass_id() {
        return class_id;
    }

    public void setClass_id(Integer class_id) {
        this.class_id = class_id;
    }

    public Integer getSubject_no() {
        return subject_no;
    }

    public void setSubject_no(Integer subject_no) {
        this.subject_no = subject_no;
    }
}
2.3 导入jar包

在这里插入图片描述

2.4 连接池和工具类
配置文件

【c3p0-config.xml】

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///stu_list?useUnicode=true&amp;characterEncoding=UTF8</property>
		<property name="user">root</property>
		<property name="password">root</property>
		<property name="acquireIncrement">2</property>
		<property name="initialPoolSize">5</property>
		<property name="minPoolSize">1</property>
		<property name="maxPoolSize">5</property>
	</default-config>
</c3p0-config>

【jedis.properties】

maxtotal=100
maxwaitmillis=3000
host=127.0.0.1
port=6379

注意:以上两个配置文件放置到src目录下。

在这里插入图片描述

工具类

【JdbcTemplateUtils.java】

package com.heima.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;

/**
 * JdbcTemplate工具类
 */
public class JdbcTemplateUtils {

    
    private static final DataSource ds = new ComboPooledDataSource();
    /**
     * 获取DataSources
     * @return
     */
    public static DataSource getDataSources() {
        return ds;
    }
    
}

【JedisUtil.java】

package com.heima.utils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ResourceBundle;

/**
 * Jedis工具类
 */
public class JedisUtil {
    private static JedisPool jedisPool;
    private static int maxtotal;
    private static int maxwaitmillis;
    private static String host;
    private static int port;

    //加载配置文件
    static {
        ResourceBundle jedisPorperties = ResourceBundle.getBundle("jedis");
        maxtotal = Integer.valueOf(jedisPorperties.getString("maxtotal"));
        maxwaitmillis = Integer.valueOf(jedisPorperties.getString("maxwaitmillis"));
        port = Integer.valueOf(jedisPorperties.getString("port"));
        host = jedisPorperties.getString("host");
    }


    //初始化连接池
    static {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxtotal);
        config.setMaxIdle(maxwaitmillis);
        jedisPool = new JedisPool(config,host, port);
    }

    /**
     * 获取jedis客户端操作对象
     * @return
     */
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }

    /**
     * 释放资源
     * @param jedis
     */
    public static void close(Jedis jedis) {
        if (null != jedis) {
            jedis.close();
        }
    }
}
3、代码实现
3.1 【stu_list.html】加载完成后发送ajax请求
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>layui</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="css/bootstrap.css">
    <style>
        .stuTable{
            width: 70%;
            margin: 20px auto;
        }
    </style>
</head>
<body>
<table class="stuTable table table-bordered " id="stuTable" >
    <caption class="text-center h2">学员列表</caption>
    <tr>
        <th>ID</th>
        <th>姓名</th>
        <th>学号</th>
        <th>性别</th>
        <th>班级</th>
        <th>学科</th>
    </tr>
</table>
<script src="js/jquery-3.3.1.js" charset="utf-8"></script>

<script>
    $.get("/getStuListServlet",function (stuData) {
        //遍历数据
        $(stuData).each(function (index, element) {
            element.sex==1?element.sex="男":element.sex="女";
            element.class_id = "就业班";
            element.subject_no = "java";
            $("<tr><td>"+element.id+"</td><td>"+element.student_name+"</td><td>"+element.student_no+"</td><td>"+element.sex+"</td><td>"+element.class_id+"</td><td>"+element.subject_no+"</td></tr>").appendTo($("#stuTable"));
        })
    });
</script>

</body>
</html>

【GetStuinfoServlet.java】 web层代码实现

package com.heima.servlet;

import com.heima.service.StudentService;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(urlPatterns = "/getStuListServlet")
public class GetStuinfoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //查询所有学员信息
        StudentService studentService = new StudentService();
        String stuJsonData = studentService.queryAllStudent();
        //响应数据
        resp.setContentType("text/json;charset=utf-8");
        resp.getWriter().println(stuJsonData);
    }
}

**【StudentService.java】**service层代码

package com.heima.service;

import com.alibaba.fastjson.JSON;
import com.heima.dao.StudentDao;
import com.heima.domain.Student;
import com.heima.utils.JedisUtil;
import redis.clients.jedis.Jedis;

import java.util.List;

public class StudentService {

    StudentDao studentDao = new StudentDao();

    /**
     * 查询所有学员信息
     * @return
     */
    public String queryAllStudent() {
        //先从redis中获取
        Jedis jedis = JedisUtil.getJedis();
        long redisBegin = System.currentTimeMillis();
        String stusData = jedis.get("stusData");
        if(null!=stusData){
            long redisEnd = System.currentTimeMillis();
            System.out.println("从redis中查询耗时:"+(redisEnd-redisBegin));
        }

        //从数据库中查询
        if (null == stusData) {
            long begin = System.currentTimeMillis();
            List<Student> studentList = studentDao.queryAll();
            long end = System.currentTimeMillis();
            System.out.println("从数据库中查询耗时:"+(end-begin));
            //将数据转化成json字符串
            stusData = JSON.toJSONString(studentList);
            //将数据存到redis中
            jedis.set("stusData", stusData);
        }
      
      //释放资源
      jedis.close();
      
        return stusData;
    }
}

【StudentDao.java】dao层代码

package com.heima.dao;

import com.heima.domain.Student;
import com.heima.utils.JdbcTemplateUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

public class StudentDao {
    /**
     * 查询所有数据
     * @return
     */
    public List<Student> queryAll() {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(JdbcTemplateUtils.getDataSources());
        String sql = "select * from stu_info";
        List<Student> studentList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Student.class));
        return studentList;
    }
}

测试:分别测试从数据库查询和从redis中查询消耗的时间;

附: 安装Redis到系统服务中

win+R==》运行:services.msc

​ 打开redis的官方安装文档:RedisService.docx

在这里插入图片描述
​ 文档中有如下安装服务和卸载服务的说明:

【安装服务】
在这里插入图片描述
​ cmd进入到Redis的安装目录下,输入以下命令:

redis-server --service-install redis.windows.conf  --loglevel verbose

在这里插入图片描述
安装完成后,查看系统服务列表(win+r 输入:services.msc),找到redis后右击启动:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值