1. Redis的简介
1.1NoSQL非关系型数据库概述
什么是NOSQL
Not Only SQL:不仅仅是SQL,指的就是非关系型数据库。以前学习过MySQL,它是关系型数据库。
非关系型数据库是关系型数据库有益的补充,不能代替关系型数据库。
非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。
NoSQL数据库的四大分类
分类 | 特点 | 代表产品 |
---|---|---|
键值存储 | 数据一般存在内存中,读写速度快(10w/s),适合作为缓存服务 | redis |
文档型数据库 | 数据结构要求不严格,适合存储结构不确定或者价值较低的数据 | mongdb |
列存储数据库 | 查找速度快,更容易进行分布式扩展,适合作为文件存储服务 | Hbase |
图形数据库 | 使用“图结构”进行存储,适合做社交网络计算等等 | Neo4j |
为什么要使用NOSQL
具体表现为对如下三高问题的解决:
High Performance - 数据库高并发访问
在同一个时间点,同时有海量的用户并发访问。往往要达到每秒上万次读写请求。关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了。
-
如天猫的双11,从凌晨0点到2点这段时间,每秒达到上千万次的访问量。
-
12306春运期间,过年回家买火车抢票的时间,用户不断查询有没有剩余票。
Huge Storage - 海量数据的存储
数据库中数据量特别大,数据库表中每天产生海量的数据。
类似QQ,微信,微博,每天用户产生海量的用户动态,每天产生几千万条记录。对于关系数据库来说,在一张几亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的。
High Scalability && High Availability- 高可扩展性和高可用性的需求
关系型数据库进行扩展和升级是比较麻烦的一样事,对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移。
非关系型数据库可以通过不断的添加服务器节点来实现扩展,而不需对原有的数据库进行维护。
作用
适合查询比较多,修改相对少的应用场景
Windows版Redis的安装
Windows版的Redis,下载地址如下:
https://github.com/microsoftarchive/redis/tags
Windows版的安装及其简单,解压Redis压缩包完成即安装完毕,注:硬盘上要预留足够多的空间(大于你的内存)
Redis的目录文件
目录或文件 | 作用 |
---|---|
redis-benchmark.exe | 性能检测工具 |
redis-check-aof.exe | AOF存储格式的修复工具 |
redis-cli.exe | 客户端命令行工具 |
redis-server.exe | Redis服务器的启动命令 |
redis.windows.conf | 在windows下的配置文件 |
Windows版Redis的启动与关闭
启动
注:在命令行下启动,不要直接去双击。
客户端
启动方法:
2. string类型的操作命令
Redis的5种数据类型
redis是一种高级的key-value的存储系统,其中value支持五种数据类型
-
string类型:字符串
-
hash类型:类似于Java中Map
-
list类型:类似于ArrayList,元素可以重复,有序的(有索引号)
-
set类型:类似于HashSet,元素是不可重复的,无序的 (没有索引号)
-
zset类型:类似于TreeSet,元素是不可重复,有序的,通过一个分数值来确定顺序
字符串类型string
在Redis中以二进制保存,没有编码和解码的过程。无论存入的是字符串、整数、浮点类型都会以字符串写入。在Redis中字符串类型的值最多可以容纳的数据长度是512M,这是以后最常用的数据类型。
常用命令
命令 | 功能 |
---|---|
set 键 值 | 添加1个字符串类型的键和值 |
setnx 键 值 | 如果键不存在才添加,存在就不添加了 |
get 键 | 通过键获取值 |
del 键 | 通过键删除值 |
setex 键 过期时间 值 | 指定一个键和值,在指定的时间之后自动删除 |
例子:
3. hash类型的操作命令
Redis中的Hash类型可以看成是键和值都是String类型的Map容器,每一个Hash可以存储4G个键值对。
该类型非常适合于存储对象的信息。如一个用户有姓名,密码,年龄等信息,则可以有username、password和age等键。它的存储结构如下:(键,字段,值)
常用命令
命令 | 功能 |
---|---|
hset 键 字段 值 | 向键中添加一个键,字段和值 |
hget 键 字段 | 通过键和字段获取值 |
hmset 键 字段 值 字段 值 | 一次设置多个字段和值 |
hmget 键 字段 字段 | 一次获取多个字段和值 |
hdel 键 字段 字段 | 通过键,删除一个或多个字段的值 |
hgetall 键 | 获取这个键下所有的字段和值 |
例子
4. list类型的操作命令
在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其左部(left)和右部(right)添加新的元素。
在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。
如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。
List中可以包含的最大元素数量是4G个。
常用命令
命令 | 行为 |
---|---|
lpush 键 元素 元素 | 从左边添加1个或多个元素 |
rpush 键 元素 元素 | 从右边添加1个或多个元素 |
lpop 键 | 从左边删除1个元素,返回被删除的元素 |
rpop 键 | 从右边删除1个元素,返回被删除的元素 |
lrange 键 开始 结束 | 获取指定范围内的元素,指定开始和结束的索引号。每个元素有2个索引号 如果要获取列表中所有的元素,索引号从0~-1 |
llen 键 | 获取列表的长度 |
例子:
5. set类型的操作命令
在Redis中,我们可以将Set类型看作为没有排序的字符集合,Set可包含的最大元素数量是4G,和List类型不同的是,Set集合中不允许出现重复的元素。
常用命令
命令 | 行为 |
---|---|
sadd 键 元素 元素 | 向集合中添加一个或多个元素 |
smembers 键 | 查询集合中所有的元素 |
sismember 键 元素 | 判断指定的元素在集合中是否存在,存在返回1,不存在返回0 |
srem 键 元素 元素 | 删除集合中一个或多个元素 |
6. Redis的通用命令
常用命令
命令 | 功能 |
---|---|
keys 匹配字符 | 查询一共有哪些键,支持通配符: * 匹配多个字符 ? 匹配一个字符 |
del 键1 键2 | 删除一个或多个键,删除任意的类型 |
exists 键 | 判断指定的键是否存在,存在返回1,不存在返回0 |
type 键 | 判断指定键的数据类型,如果键不存在返回none |
select 数据库编号 | 切换数据库 |
move 键 数据库编号 | 将指定的键移到另一个数据库中 |
expire 键 秒 | 指定键多久过期,单位是秒 |
ttl 键 | 显示还有多久过期,正数表示过期的秒数 返回-1表示永不过期,返回-2表示这个键不存在 |
例子
7. Redis的持久化:RDB方式
什么是Redis的持久化:
把内存中的数据写到硬盘文件上的过程,称为持久化。
Redis持久化的两种方式:
-
RDB是它默认的存储方式:Redis DataBase 以二进制的方式保存所有的数据本身
-
AOF默认是不打开的,需要配置:Append Only File 以日志的方式(文本文件)保存所有的操作步骤。
RDB持久化机制优点
-
方便备份与恢复
整个Redis数据库将只包含一个文件,默认是dump.rdb,这对于文件备份和恢复而言是非常完美的。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
-
性能最大化
对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是分叉出子进程,由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
-
启动效率更高
相比于AOF机制,如果数据集很大,RDB的启动效率会更高
RDB持久化机制缺点
-
不能完全避免数据丢失
因为RDB是每隔一段时间写入数据,所以系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
-
会导致服务器暂停的现象
由于RDB是通过子进程来协助完成数据持久化工作的,因此当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
RDB持久化机制的配置
在redis.windows.conf配置文件中的SNAPSHOTTING中有如下说明:
语法 | 说明 |
---|---|
save <时间间隔> <修改键数> | 同时满足两个条件,在指定的时间以后, 修改了指定数量的键(增删改),就持久化一次 |
如下面配置的是RDB方式数据持久化时机,必须两个条件都满足的情况下才进行持久化的操作:
关键字 | 时间(秒) | 修改键数 | 解释 |
---|---|---|---|
save | 900 | 1 | 在15分钟修改了1个键 |
save | 300 | 10 | 在5分钟修改了10个键 |
save | 60 | 10000 | 在1分钟修改了1万个键 |
8. Jedis的API介绍
Jedis的介绍
Redis不仅可以使用命令来操作,现在基本上主流的语言都有API支持,比如Java、C#、C++、PHP、Node.js、Go等。在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis等其中官方推荐使用Jedis和Redisson。 Jedis操作redis需要导入jar包如下:
Jedis类常用方法
注:每个方法就是redis中的命令名,方法的参数就是命令的参数。每个Jedis对象似于JDBC中Connection对象。
连接和关闭 | 功能 |
---|---|
new Jedis(host, port) | 创建连接,指定2个参数:主机名,端口号 |
void close() | 每次使用完毕必须关闭连接 |
对string操作的方法 | 说明 |
---|---|
set(String key,String value) | 添加字符串类型的键和值 |
String get(String key) | 通过键获取值 |
del(String ... keys) | 删除一个或多个键 |
例子
package com.it.jedis;
import redis.clients.jedis.Jedis;
/**
* Jedis的基本操作
*/
public class Demo1 {
public static void main(String[] args) {
//1.创建连接
Jedis jedis = new Jedis("localhost", 6379);
//2.使用set方法添加键和值
jedis.set("person", "张三");
String person = jedis.get("person");
System.out.println("值:" + person);
//3.使用完毕需要关闭
jedis.close();
}
}
9. Jedis连接池的使用
jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的连接池技术,jedis连接池在创建时初始化一些连接对象存储到连接池中,使用jedis连接资源时不需要自己创建jedis对象,而是从连接池中获取一个资源进行redis的操作。使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用。
Jedis连接池API
JedisPoolConfig配置类 | 功能说明 |
---|---|
JedisPoolConfig() | 创建一个配置对象 |
void setMaxTotal() | 指定最大连接数 |
void setMaxWaitMillis() | 指定最长等待时间,单位是毫秒 |
JedisPool连接池类 | 说明 |
---|---|
JedisPool(配置对象,服务器名,端口号) | 创建连接池 |
Jedis getResource() | 从连接池中获取一个连接对象 |
JedisPool的基本使用
需求:
使用连接池优化jedis操作,从连接池中得到一个创建好的Jeids对象,并且使用这个Jedis对象。向Redis数据库写入一个set集合,并且取出集合。打印到控制台,并且查看数据库中信息。
开发步骤
-
创建连接池配置对象,设置最大连接数10,设置用户最大等待时间2000毫秒
-
通过配置对象做为参数,创建连接池对象
-
从连接池里面获取jedis连接对象,执行redis命令。
-
执行redis命令sadd写入set集合类型的数据:students=白骨精,孙悟空,猪八戒
-
执行redis命令smembers读取集合中的数据
-
输出读取的数据
-
关闭连接对象(通常连接池不关闭)
例子
package com.it.jedis;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Set;
/**
* 连接池的使用
*/
public class Demo2 {
public static void main(String[] args) {
//1.创建配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(30);
config.setMaxWaitMillis(2000);
//2.通过配置对象创建连接池对象
JedisPool pool = new JedisPool(config, "localhost", 6379);
//3.从连接池中获取一个连接对象
Jedis jedis = pool.getResource();
//4.使用
jedis.sadd("students", "孙悟空", "牛魔王", "白骨精");
Set<String> students = jedis.smembers("students");
System.out.println(students);
//5.使用后要关闭连接对象
jedis.close();
//pool.close(); 一般不用关闭连接池
}
}
10. Jedis连接池工具类的实现
代码
jedis.properties配置文件
# 主机名
host=localhost
# 端口号
port=6379
# 最大连接数
maxTotal=20
# 最长等待时间
maxWaitMillis=3000
JedisUtils.java
package com.it.utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Properties;
import java.util.ResourceBundle;
/**
* Jedis工具类
* 1. 读取配置文件
* 2. 创建连接池
* 3. 获取连接对象
*/
public class JedisUtils {
private static JedisPool pool = null;
//读取配置文件
static {
//1. 创建资源绑定对象,参数:配置文件的主文件名,不用指定后缀名
ResourceBundle bundle = ResourceBundle.getBundle("jedis");
//2. 指定键获取值
String host = bundle.getString("host");
int port = Integer.parseInt(bundle.getString("port"));
int maxTotal = Integer.parseInt(bundle.getString("maxTotal"));
int maxWaitMillis = Integer.parseInt(bundle.getString("maxWaitMillis"));
//创建配置对象 -> 创建连接池 -> 获取连接对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxWaitMillis(maxWaitMillis);
config.setMaxTotal(maxTotal);
//创建连接池
pool = new JedisPool(config, host, port);
}
/**
* 从连接池中获取连接对象
* @return
*/
public static Jedis getJedis() {
Jedis jedis = pool.getResource();
System.out.println("获取连接对象:" + jedis);
return jedis;
}
}
11.RedisTemplate的使用
Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅,并对spring 3.1 cache进行了实现。
RedisTemplate中API使用
1、pom.xml依赖
<!--Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置文件
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000ms
3、注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
4.RedisTemplate的直接方法
1、删除单个key
// 删除key
public void delete(String key){
redisTemplate.delete(key);
}
2、删除多个key
// 删除多个key
public void deleteKey (String ...keys){
redisTemplate.delete(keys);
}
3、指定key的失效时间
// 指定key的失效时间
public void expire(String key,long time){
redisTemplate.expire(key,time,TimeUnit.MINUTES);
}
4、根据key获取过期时间
// 根据key获取过期时间
public long getExpire(String key){
Long expire = redisTemplate.getExpire(key);
return expire;
}
5、判断key是否存在
// 判断key是否存在
public boolean hasKey(String key){
return redisTemplate.hasKey(key);
}
5、String类型相关操作
1、添加值
//1、通过redisTemplate设置值
redisTemplate.boundValueOps("StringKey").set("StringValue");
redisTemplate.boundValueOps("StringKey").set("StringValue",1, TimeUnit.MINUTES);
//2、通过BoundValueOperations设置值
BoundValueOperations stringKey = redisTemplate.boundValueOps("StringKey");
stringKey.set("StringVaule");
stringKey.set("StringValue",1, TimeUnit.MINUTES);
//3、通过ValueOperations设置值
ValueOperations ops = redisTemplate.opsForValue();
ops.set("StringKey", "StringVaule");
ops.set("StringValue","StringVaule",1, TimeUnit.MINUTES);
2、设置过期时间(单独设置)
redisTemplate.boundValueOps("StringKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("StringKey",1,TimeUnit.MINUTES);
3、获取值
//1、通过redisTemplate设置值
String str1 = (String) redisTemplate.boundValueOps("StringKey").get();
//2、通过BoundValueOperations获取值
BoundValueOperations stringKey = redisTemplate.boundValueOps("StringKey");
String str2 = (String) stringKey.get();
//3、通过ValueOperations获取值
ValueOperations ops = redisTemplate.opsForValue();
String str3 = (String) ops.get("StringKey");
4、删除key
Boolean result = redisTemplate.delete("StringKey");
5、顺序递增
redisTemplate.boundValueOps("StringKey").increment(3L);
6、顺序递减
redisTemplate.boundValueOps("StringKey").increment(-3L);
5、Hash类型相关操作
1、添加值
//1、通过redisTemplate设置值
redisTemplate.boundHashOps("HashKey").put("SmallKey", "HashVaue");
//2、通过BoundValueOperations设置值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
hashKey.put("SmallKey", "HashVaue");
//3、通过ValueOperations设置值
HashOperations hashOps = redisTemplate.opsForHash();
hashOps.put("HashKey", "SmallKey", "HashVaue");
2、设置过期时间(单独设置)
redisTemplate.boundValueOps("HashKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("HashKey",1,TimeUnit.MINUTES);
3、添加一个Map集合
HashMap<String, String> hashMap = new HashMap<>();
redisTemplate.boundHashOps("HashKey").putAll(hashMap );
4、设置过期时间(单独设置)
redisTemplate.boundValueOps("HashKey").expire(1,TimeUnit.MINUTES);
redisTemplate.expire("HashKey",1,TimeUnit.MINUTES);
5、提取所有的小key
//1、通过redisTemplate获取值
Set keys1 = redisTemplate.boundHashOps("HashKey").keys();
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
Set keys2 = hashKey.keys();
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
Set keys3 = hashOps.keys("HashKey");
6、提取所有的value值
//1、通过redisTemplate获取值
List values1 = redisTemplate.boundHashOps("HashKey").values();
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
List values2 = hashKey.values();
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
List values3 = hashOps.values("HashKey");
7、根据key提取value值
//1、通过redisTemplate获取
String value1 = (String) redisTemplate.boundHashOps("HashKey").get("SmallKey");
//2、通过BoundValueOperations获取值
BoundHashOperations hashKey = redisTemplate.boundHashOps("HashKey");
String value2 = (String) hashKey.get("SmallKey");
//3、通过ValueOperations获取值
HashOperations hashOps = redisTemplate.opsForHash();
String value3 = (String) hashOps.get("HashKey", "SmallKey");