Redis简单介绍与使用
NOSQL
什么是NOSQL
NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”
是一项全新的数据库理念,泛指非关系型的数据库。
NOSQL解决什么问题
web程序不再仅仅专注在功能上,同时也在追求性能
High performance
对数据库高并发读写的需求
现在数据库并发负载非常高,往往要达到每秒上万次读写请求
关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写 数据请求,硬盘IO就已经无法承受了
Huge Storage
对海量数据的高效率存储和访问的需求
对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的
High Scalability && High Availability-
对数据库的高可扩展性和高可用性的需求
对于很多需要提供24小时不间断服务的网站来说,
对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移
主流的NOSQL产品
主流产品
键值(Key-Value)存储数据库-redis
主要使用内存, 有两种持久化方案, 速度非常快,
一般做分布式缓存使用
文档型数据库-MongoDB
主要使用硬盘存储, 所以不会担心数据丢失, 速度介于redis和传统数据库之间.
但是mongodb更擅长存储大文本数据, 以及一些非结构化数据,
mongodb比redis的数据类型更加丰富.
例如: 存储小说网站的小说, 存储电商网站的评论等这些数据
redis概述
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库
官方提供测试数据
50个并发执行100000个请求
读的速度是110000次/s
写的速度是81000次/s
redis的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等)
聊天室的在线好友列表
任务队列。(秒杀、抢购、12306等等)
应用排行榜
网站访问统计
数据过期处理(可以精确到毫秒
分布式集群架构中的session分离
业务流程
获取数据的时候先从redis中获取, 如果获取到数据则直接返回, 就不用访问数据库了
如果获取不到数据, 可以从数据库中查询, 查询到后放入redis中一份, 下回就可以直接从redis中查询到
这样大大降低了数据库的高并发访问压力.
持久化方案
RDB(默认) 分时持久化
可以在配置文件中设定, 多长时间持久化一次, 持久化次数少也就是操作硬盘的次数少,
速度快. 但是如果在没有完成持久化前, 如果服务器断电, 则内存中没有持久化的数据会丢失.
AOF 实时持久化
每次向redis中做增删改操作, 都会将数据持久化到硬盘上, 数据可靠性高, 不会丢失,但是速度慢
redis安装
链接: https://pan.baidu.com/s/1pS_jPx1WenVaO3nwYRdbSQ 提取码: ac2e
windows
window版的安装及其简单,
解压Redis压缩包完成即安装完毕
双击Redis目录中redis-server.exe可以启动redis服务,Redis服务占用的端口是6379
关闭Redis的控制台窗口就可以关闭Redis服务
linux
-
将redis在Linux的安装包上传到/usr/local当中
-
解压
tar -xvf redis-4.0.9.tar.gz
-
编译安装
进入到redis目录
执行命令:- make
- make install PREFIX='/usr/local/redis-4.0.9/6379'
-
启动
进入到/usr/local/redis-4.0.9/6379/bin目录当中
执行命令: ./redis-server
-
修改配置文件
把/usr/local/redis-4.0.9/目录下的配置文件复制一份到6379目录下
命令:cp /usr/local/redis-4.0.9/redis.conf /usr/local/redis-4.0.9/6379/bin/
修改配置文件
vim redis.conf
bind 127.0.0.1 # 将这行代码注释,监听所有的ip地址,外网可以访问
protected-mode no # 把yes改成no,允许外网访问
daemonize yes # 把no改成yes,后台运行
- 重新启动
./redis-server redis.conf
ps -ef|grep redis
Redis的数据类型
redis是一种高级的key-value的存储系统,其中value支持五种数据类型
Redis的5种数据类型
1. 字符串(String)
2. 哈希(hash)
3. 字符串列表(list)
4. 字符串集合(set)
5. 序字符串集合(sorted set)
key的定义注意点:
key不要太长,最好不要操作1024个字节,这不仅会消耗内存还会降低查找效率
key不要太短,如果太短会降低key的可读性
在项目中,key最好有一个统一的命名规范
基本操作
在redis-4.0.9/6379/bin目录下输入命令
./redis-cli
字符串类型string
概述
设定key持有指定的字符串value,如果该key存在则进行覆盖操作。总是返回”OK”
操作
- set key value 设置key值
- get key 获取key值
获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息,
- del key 删除key值
哈希类型hash
概述
Redis中的Hash类型可以看成具有String Key和String Value的map容器
所以该类型非常适合于存储值对象的信息
操作
- hset key field value 为指定的key设定field/value对(键值对)
hset myhash username joker
存入hash类型值 myhast 存的值为 username:joker - hget key field 返回指定的key中的field的值
hget myhash username
- hdel key field [field … ]
可以删除一个或多个字段,多个之间空格隔开,返回值是被删除的字段个数
- hgetall key 可以获取该键的所有数据
列表类型list
概述
在Redis中,List类型是按照插入顺序排序的字符串链表。
和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素
在插入时,如果该键并不存在,Redis将为该键创建一个新的链表
与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除
List中可以包含的最大元素数量是4294967295
操作
- lpush key values[value1 value2…]
在指定的key所关联的list的头部插入所有的values,
如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据。
插入成功,返回元素的个数
-
lpop key
返回并弹出指定的key关联的链表中的第一个元素,即头部元素
如果该key不存在,返回nil;若key存在,则返回链表的头部元素。
-
rpop key
从尾部弹出元素。
-
lrange key 遍历该键的所有数据
lrange key 0 -1 返回所有
lrange key 0 2 返回从0开始 0 1 2
集合类型set
概述
在Redis中,我们可以将Set类型看作为没有排序的字符集合
和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作
Set集合中不允许出现重复的元素。
操作
- sadd key values[value1、value2…]
向set中添加数据,如果该key的值已有则不会重复添加
- smembers key
获取set中所有的成员
- srem key members[member1、member2…]
删除set中指定的成员
有序集合类型sortset
在redis中,可以保证不重复的元素,仍然可以进行排序
- zadd key values[value1、value2…]
例:zadd mysort 5 zs 10 lisi 7 wc 8 xk
- zrange key 索引 索引
查看排序 索引小的排在前
- zrem key value
删除sort值
Redis的通用命令
- keys pattern
获取所有与pattern匹配的key,返回所有与该key匹配的keys。
*表示任意一个或多个字符,?表示任意一个字符
- del key1 key2…
删除指定的key
- exists key
判断该key是否存在,1代表存在,0代表不存在
- type key
获取指定key的类型。该命令将以字符串的格式返回
返回的字符串为string、list、set、hash,如果key不存在返回none
- EXPIREAT key timestamp设置key过期时间
Redis的持久化
概述
Redis的高性能是由于其将所有数据都存储在了内存中
为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化;Redis支持两种方式的持久化,可以单独使用其中一种或将二者结合使用。
一种是RDB方式,一种是AOF方式。
RDB持久化(默认支持,无需配置)
该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
AOF持久化
该机制将以日志的形式记录服务器所处理的每一个写操作
在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
无持久化
我们可以通过配置的方式禁用Redis服务器的持久化功能
这样我们就可以将Redis视为一个功能加强版的memcached了
redis可以同时使用RDB和AOF
RDB持久化机制
RDB持久化机制优点
一旦采用该方式,那么你的整个Redis数据库将只包含一个文件
这对于文件备份而言是非常完美的
RDB持久化机制缺点
如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟
快照触发条件
客户端执行命令save和bgsave会生成快照;
根据配置文件save m n规则进行自动快照;
主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照;
客户端执行数据库清空命令FLUSHALL时候,触发快照;
客户端执行shutdown关闭redis时,触发快照;
RDB持久化机制的配置
在redis.conf进行修改配置
- save m n
配置快照(rdb)促发规则,格式:save
save 900 1 900秒内至少有1个key被改变则做一次快照
save 300 10 300秒内至少有10个key被改变则做一次快照
save 60 10000 60秒内至少有10000个key被改变则做一次快照
#关闭该规则使用save “ ”
- dbfilename dump.rdb
rdb持久化存储数据库文件名,默认为dump.rdb - stop-write-on-bgsave-error yes
yes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no表明忽略错误继续写文件。 - rdbchecksum yes
在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。 - dir "./"
数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限 - rdbcompression yes
是否开启RDB文件压缩,该功能可以节约磁盘空间
AOF持久化机制
AOF概述
当redis存储非临时数据时,为了降低redis故障而引起的数据丢失,redis提供了AOF(Append Only File)持久化,
从单词意思讲,将命令追加到文件。AOF可以将Redis执行的每一条写命令追加到磁盘文件(appendonly.aof)中
在redis启动时候优先选择从AOF文件恢复数据。由于每一次的写操作,redis都会记录到文件中,所以开启AOF持久化会对性能有一定的影响
AOF持久化数据丢失更少,其消耗内存更少(RDB方式执行bgsve会有内存拷贝)
开启AOF持久化
默认情况下,redis是关闭了AOF持久化,开启AOF通过配置appendonly为yes开启
将appendonly修改为yes,开启aof持久化机制,默认会在目录下产生一个appendonly.aof文件
我们修改配置文件或者在命令行直接使用config set修改,在用config rewrite同步到配置文件。通过客户端修改好处是不用重启redis,AOF持久化直接生效
config get appendonly:查询配置状态
config set appendonly yes:修改配置
config rewrite:写入到redis.conf中
配置
appendfsync:always 每执行一次更新命令,持久化一次
appendfsync:everysec 每秒钟持久化一次
appendfsync:no 不持久化
RDB-AOF混合持久化
通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改。
Redis设置密码
获取密码
config get requirepass
设置密码
config set requirepass 123456
当有密码的时候登录时需要密码登录
auth 密码
取消密码
config set requirepass ''
jedis
使用Jedis操作redis需要导入jar包如下:
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
jedis的基本操作
public void testJedis(){
//1 设置ip地址和端口
Jedis jedis = new Jedis("localhost", 6379);
//2 设置数据
jedis.set("name", "fmjava");
//3 获得数据
String name = jedis.get("name");
System.out.println(name);
//4 释放资源
jedis.close();
}
jedis连接池的基本概念
jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术
示例代码
public void testJedisPool(){
//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", "fmjava");
//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();
}
}
}
SpringDataRedis
Spring-data-redis概述
Spring-data-redis是spring大家族的一部分
提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装
RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅
spring-data-redis功能
- 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对jedis客户端中大量api进行了归类封装
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
ValueOperations:简单K-V操作
Spring Data Redis入门程序
- 创建maven工程 jar
- 引入Spring/Jedis和SpringDataRedis依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<!-- 缓存 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
</dependencies>
- 在src/main/resources建立redis-config.properties
redis.host=192.168.0.108
redis.port=6379
redis.pass=
redis.database=0
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=true
- 在src/main/resources创建applicationContext-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath*:*.properties" />
<!-- redis 相关配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="JedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}"
p:port="${redis.port}"
p:password="${redis.pass}"
p:pool-config-ref="poolConfig"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
</beans>
- 建立TestString测试字符串操作方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestString {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSet() {
redisTemplate.boundValueOps("name").set("joker");
}
@Test
public void testGet() {
String name = (String) redisTemplate.boundValueOps("name").get();
System.out.println("name=" + name);
}
@Test
public void testDelete() {
redisTemplate.delete("name");
}
}
- 建立TestList测试List操作方法
Lpush
Rpush
Range
testDelete
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestList {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testLpush() {
redisTemplate.boundListOps("myListKey").leftPush("001");
redisTemplate.boundListOps("myListKey").leftPush("002");
redisTemplate.boundListOps("myListKey").leftPush("003");
redisTemplate.boundListOps("myListKey").leftPush("004");
}
@Test
public void testRpush() {
redisTemplate.boundListOps("myListKey").rightPush("001");
redisTemplate.boundListOps("myListKey").rightPush("002");
redisTemplate.boundListOps("myListKey").rightPush("003");
redisTemplate.boundListOps("myListKey").rightPush("004");
}
@Test
public void testRange() {
List<String> myListKey = redisTemplate.boundListOps("myListKey").range(0, -1);
for (String s : myListKey) {
System.out.println("value=" + s);
}
}
@Test
public void testDelete() {
redisTemplate.delete("myListKey");
}
}
- 建立TestHash测试hash
hash格式
Put 设置hash值
Get 获取hash值
entries 遍历所有key-value
delete
删除key的某个值
删除key的所有值
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestHash {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testPut() {
redisTemplate.boundHashOps("keyname1").put("name", "zs");
redisTemplate.boundHashOps("keyname1").put("age", "20");
redisTemplate.boundHashOps("keyname1").put("phone", "121");
redisTemplate.boundHashOps("keyname1").put("email", "1@qq.com");
}
@Test
public void testGetOne() {
String name = (String)redisTemplate.boundHashOps("keyname1").get("name");
System.out.println("name =" + name);
}
@Test
public void testGetAll() {
//获取所有的entries
Map<String, String> testHash = (Map<String, String>)redisTemplate.boundHashOps("keyname1").entries();
Set<Map.Entry<String, String>> entries = testHash.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println("key=" + entry.getKey());
System.out.println("value=" + entry.getValue());
}
}
@Test
public void testDeleteOne() {
redisTemplate.boundHashOps("keyname1").delete("name");
}
@Test
public void testDeleteAll() {
redisTemplate.delete("keyname1");
}
}
- 存储对象
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private Integer age;
private char sex;
public Person(String name, Integer age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestObject {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void setObject(){
Person person = new Person("joker", 20, '男');
redisTemplate.boundValueOps("person").set(person);
}
@Test
public void getObject(){
Person person=(Person)redisTemplate.boundValueOps("person").get();
}
}
- 真实业务存储对象
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.List;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestObject {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void setObject(){
Person person = new Person("joker", 20, '男');
Person person1 = new Person("joker1", 21, '男');
Person person2 = new Person("joker1", 21, '男');
Person person3 = new Person("joker1", 21, '男');
ArrayList<Person> personArrayList=new ArrayList<>();
personArrayList.add(person);
personArrayList.add(person1);
personArrayList.add(person2);
personArrayList.add(person3);
/*分业务*/
redisTemplate.boundHashOps("userService").put("person",personArrayList);
}
@Test
public void getObject(){
List<Person> people=(List<Person>) redisTemplate.boundHashOps("userService").get("person");
System.out.println(people);
}
}
SpringMVC整合redis
- 在SSM基础上添加redis相关依赖
<!-- Jackson Json处理工具包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
- 添加redis配置文件
properties/redis-config.properties
redis.host=192.168.0.108
redis.port=6379
redis.pass=
redis.database=0
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=true
spring/applicationContext-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath*:/properties/*.properties" />
<!-- redis 相关配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="JedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}"
p:port="${redis.port}"
p:password="${redis.pass}"
p:pool-config-ref="poolConfig"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
</beans>