09_Redis(NOSQL)
NOSQL介绍
NOSql,全称 not only sql ,不仅仅是sql,泛指非关系型数据库。
非关系与关系型数据库的区别
image.png为什么需要NOSql?
因为是内存操作数据,非常快,会让系统性能大大提高。(解决了3高问题,高并发,高海量,高可用)
高并发:同一个时间点并发访问量非常大。
高海量:一个人访问的数据非常大,查询一个表,表中的数据有上亿条。
高可用:服务器崩溃了,服务器需要立刻重启后数据依然可用。
tips:购物秒杀(高并发)
以后到底用关系型数据库还是非关系型数据库?
都用。
image.png
Redis下载安装:
1.windows版本,微软提供
https://github.com/MSOpenTech/redis/tags
2.linux版本,官方提供:http://redis.io/download
Redis目录结构:
image.pngtips:
1.Redis以什么方式存取数据:
键值对
2.Redis软件
客户端:cli
服务端:Server
3.Redis服务端使用端口:
6379
Redis常用数据类型
String(常用),Hash,list,set,sorted set(z-set)
image.png
String
字符串类型是 Redis 中最为基础的数据存储类型,它在 Redis 中以二进制保存,没有编码和解码的过程。无论存入的是字符串、整数、浮点类型都会以字符串写入。在 Redis 中字符串类型的 Value 最多可以容纳的数据长度是 512M。这是以后最常用的数据类型。
操作命令语法:
image.png
Hash
Redis 中的 Hash 类型可以看成具 String 的键和 String 的值 Map 容器,每一个 Hash 可以存储 40(42 亿 9千多个)亿个键值对。
操作命令语法:
image.png
应用场景:
高并发的下单数据
先写入redis的list类型数据(链表,有序的),再通过链表一个一个有序删除获取删除的数据(下单数据),再写入数据库。
set
特点:无序、不重复
Set 可包含的最大元素数量是 40 亿,和 List 类型不同的是,Set 集合中不允许出现重复的元素。
操作语法指令:
image.png
sorted set(z-set)
image.png其他类型
http://www.runoob.com/redis/redis-sorted-sets.html
R edis客户端显示接界
RedisDesktopMannager
操作命令语法:
image.png
Redis持久化策略
redis服务器关闭所有内存数据都会丢失吗?
不会全部丢失,默认只会丢失一部分,因为redis有持久化机制,redis会将内存数据符合条件时进行持久化,在redis重启的时候会恢复持久化的数据,这就是内存数据不会全部丢失。
RDB(快照策略)
rdb(redis data base)持久化策略就是在符合一定条件下将内存所有数据持久化到磁盘中dump.rdb文件中。RDB策略是redis默认持久化策略。也叫快照策略
tips:
为什么叫快照策略?
因为磁盘持久化的数据为某一个时间点的内存所有数据。
RDB策略的配置:
image.png
RDB优缺点
优:持久化的频率不高,意味着Redis提供给用户操作数据性能更高
缺:持久化的频率不高,意味着丢失数据验证严重,数据安全性低。
AOF策略
默认没有开启的策略,它的特点持久化的频率更高了,默认每秒持久化1次。每一秒内将最新的写入与删除的命令进行持久化。
需要修改配置文件redis.windows.conf进行开启AOF策略,如下操作
开启AOF后,持久化策略有3个
image.png
AOF默认是采用的策略是每秒持久化一次,会导致持久化文件随着时间不断增大,AOF会记录每一个key所有修改操作的过程。
常见面试题
image.pngtips:
RDB和AOF以后到底推荐使用哪一个呢?
1.官方推荐2个都使用,因为可以保证数据高可用。
2.如果希望高可用,才开AOF,否则只建议使用RDB,因为AOF会降低redis的性能(cpu超过60%都会选择关闭AOF)。
3.redis.3.0版本以后默认RDB和AOF都开启了
Jedis的使用
使用java代码来造作redis服务器存取数据。
tips:
tomcat服务器有内存空间,和redis是内存数据库,只用tomcat的内存不够用吗?
答:tomcat的内存主要用于计算、业务逻辑处理redis内存主要负责存取数据
原则:尽量tomcat少存储数据,主要进行计算
Jedis介绍
Jedis的API方法
image.pngjedis的使用步骤
- 导入jedis的jar包
- 利用jedis的api方法操作redis数据库
Jedis使用基本代码
import redis.clients.jedis.Jedis;
import java.util.List;
public class JedisTest1_Basic {
public static void main(String[] args) {
//目标:使用jedis操作redis存取数据
//1.获取连接对象Jedis
Jedis jedis = new Jedis("localhost", 6379);
//2.写入一个字符串数据
jedis.set("name","张三");
//3.写入一个List集合数据
jedis.lpush("myList2","a","b","c");
jedis.rpush("myList2","one","two","three");
//4.读取数据并打印
//读取字符串
String name = jedis.get("name");
//读取list集合
List<String> myList2 = jedis.lrange("myList2", 0, -1);
//打印
System.out.println("name="+name);
System.out.println("myList2="+ myList2);
//5.连接关闭
jedis.close();
}
}
tips:
1.Jedis的作用:
使用java代码操作Redis数据库
2.Jedis使用完成后注意:
关闭。
Jedis连接池
使用连接池控制连接的数量,保证服务器的稳定性。
使用Jedis连接池优化代码
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
public class JedisTest2_Pool {
public static void main(String[] args) {
//目标:使用jedis操作redis存取数据
//1.从连接池对象中获取连接对象Jedis
//1.1 创建连接池配置对象
JedisPoolConfig config= new JedisPoolConfig();
config.setMaxTotal(10);//最大连接数
config.setMaxWaitMillis(30000); //30秒,用户等待连接的最大超时时间,单位:毫秒
//1.2 创建连接池对象
JedisPool jedisPool = new JedisPool(config,"localhost",6379);
//1.3 从连接池获取连接
Jedis jedis = jedisPool.getResource();
//2.写入一个字符串数据
jedis.set("name","张三");
//3.写入一个List集合数据
jedis.lpush("myList2","a","b","c");
jedis.rpush("myList2","one","two","three");
//4.读取数据并打印
//读取字符串
String name = jedis.get("name");
//读取list集合
List<String> myList2 = jedis.lrange("myList2", 0, -1);
//打印
System.out.println("name="+name);
System.out.println("myList2="+ myList2);
//5.连接关闭,将连接放回连接池
jedis.close();
//6.关闭(暂时关闭,在真正使用的时候是不关闭)
jedisPool.close();
}
}
tips:
连接池的一般配置参数:
用户等待超时时间
最大连接数
使用工具类优化连接池操作代码
使用工具类优化连接池操作的好处:
解决代码的冗余
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ResourceBundle;
public class JedisUtils {
//定义连接池对象
private static JedisPool jedisPool;
//使用静态代码块初始化连接池
static{
//1.解析配置文件获取参数数据
//ResourceBundle类专门用于解析properties配置文件,可以根据类路径下文件名字就可以解析
ResourceBundle resourceBundle = ResourceBundle.getBundle("jedis");
int maxTotal = Integer.parseInt(resourceBundle.getString("maxTotal"));
int maxWaitMillis = Integer.parseInt(resourceBundle.getString("maxWaitMillis"));
String host = resourceBundle.getString("host");
int port = Integer.parseInt(resourceBundle.getString("port"));
//2.创建连接池配置对象
JedisPoolConfig config= new JedisPoolConfig();
config.setMaxTotal(maxTotal);//最大连接数
config.setMaxWaitMillis(maxWaitMillis); //30秒,用户等待连接的最大超时时间,单位:毫秒
//3.创建连接池对象
jedisPool = new JedisPool(config,host,port);
}
/*目标:提供一个从连接池获取连接的方法*/
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
疑问:
问题:我们都知道缓存的使用,第一次从磁盘数据库获取,以后都从缓存获取,那么磁盘数据库数据更新了,缓存没有更新,导致缓存数据过期了,怎么办?
更新缓存:
方式1:删除缓存的数据,下一次查询自然从mysql数据库获取再写入缓存
方式2:使用定时器定时更新缓存
方式3:更新数据库的同时,更新缓存