目录
Redis 简介
在使用关系型数据库的时候如果发生海量的用户请求对表进行读取,修改等等会导致关系型数据库的崩溃,而且读取速率低下应对高并发的情况处理能力不足,数据关系复杂,扩展性差,不便于大规模集群,这时就有了非关系型数据库
非关系型数据库Nosql
降低了磁盘的IO流次数,通过内存存储的方式
去除了数据间的关系,越是简单越好,通过不存储数据关系只存储数据的形式
可扩容,可伸缩 灵活的数据模型 大数据量下高性能
其中最常用的就是Redis
Redis特征
- 数据间没有必然的关联关系
- 内部采用单线程机制进行工作
- 高性能。官方提供测试数据,50个并发执行100000 个请求,读的速度是110000 次/s,写的速度是81000次/s。
- 多数据类型支持
◆ 字符串类型 string
◆ 列表类型 list
◆ 散列类型 hash
◆ 集合类型 set
◆ 有序集合类型 zset/sorted_set - 支持持久化,可以进行数据灾难恢复
下载和安装Redis
直接在liunx中解压
创建conf和data目录用来存放配置文件和日志文件
在conf中修改配置文件
这里吧端口改成了6380 IP地址更改成0.0.0.0方便后面访问日志文件存放在打他目录下文件名为logs-6380.log
配置完成以后在src下启动
通过配置文件启动
遇到报错,说是无法读取logs-6380.log
权限不够,这里可以去更改配置文件权限,也可以把自己用户变成管理员进行操作
在更改完管理员用户后成功运行
然后可以查看是否存在6380的端口服务
端口正常运行就可以进入redis服务了
这就说明成功启动了。
Redis的基础数据类型
redis 数据存储格式
- redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储
- 数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串
Redis 数据类型(5种常用)
⚫ string
⚫ hash
⚫ list
⚫ set
⚫ sorted_set/zset(应用性较低)
String类型
1. 数据操作不成功的反馈与数据正常操作之间的差异
◆ 表示运行结果是否成功
⚫ (integer) 0 → false 失败
⚫ (integer) 1 → true 成功
◆ 表示运行结果值
⚫ (integer) 3 → 3 3个
⚫ (integer) 1 → 1 1个
2. 数据未获取到时,对应的数据为(nil),等同于null
3. 数据最大存储量:512MB
4. string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算
5. 按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis 数值上限范围,将报错
9223372036854775807(java中Long型数据最大值,Long.MAX_VALUE)
6. redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响
主要用于高频访问信息显示控制
- 在redis中为大V用户设定用户信息,以用户主键和属性值作为key,
后台设定定时刷新策略即可
eg: user:id:3506728370:fans → 12210947
eg: user:id:3506728370:blogs → 6164
eg: user:id:3506728370:focuses → 83
- 也可以使用json格式保存数据
eg: user:id:3506728370 → {“fans”:12210947“blogs”:6164“ focuses ”:83
hash类型
如果是对对象进行一个存储用String就显得笨重这时候就可以通过hash结构来存储
key -> field_01 -> value_01的形式来存储
关系hash的操作
hash类型数据的操作注意点
1. hash类型中value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
2. 每个 hash 可以存储 2^32 - 1 个键值对
3. hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计
的,切记不可滥用,更不可以将hash作为对象列表使用
4. hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈
应用场景
销售手机充值卡的商家对移动、联通、电信的30元、50元、100元商品推出抢购活动,每种商品抢购上限1000张
- 以商家id作为key
- 将参与抢购的商品id作为field
- 将参与抢购的商品数量作为对应的value
- 抢购时使用降值的方式控制产品数量
List类型
存储多个数据,并对数据进入存储空间的顺序进行区分
一个存储空间保存多个数据,且通过数据可以体现进入顺序
保存多个数据,底层使用双向链表存储结构实现
list的操作
list 类型数据操作注意事项
1. list中保存的数据都是string类型的,数据总容量是有限的,最多2^32- 1元素 (4294967295)。
2. list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
3. 获取全部数据操作结束索引设置为-1
4. list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加载
应用场景
企业运营过程中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出?
可以用list来解决
- 依赖list的数据具有顺序的特征对信息进行管理
- 使用队列模型解决多路信息汇总合并的问题
- 使用栈模型解决最新消息的问题
set 类型
新的存储需求:存储大量的数据,在查询方面提供更高的效率
需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
set 类型数据的基本操作
set 类型数据操作的注意事项
- set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
- set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
key常用指令
数据库的常用指令
java中用jedis操作redis
jar包导入
下载地址:https://mvnrepository.com/artifact/redis.clients/jedis
基于maven
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
客户端的连接
利用Jedis jedis = new Jedis(“IP地址”,端口号;
来连接redis,通过调用jedis中的get/set方法可以对其进行操作
package com.jedis;
import redis.clients.jedis.Jedis;
import java.util.Set;
public class JedisTest {
public static void main(String[] args) {
//创建jedis对象 传入ip地址和端口号
Jedis jedis = new Jedis("192.168.23.32",6380);
//用set方法创建一个键值
jedis.set("six","哔哩哔哩1");
jedis.set("name","蔡徐坤1");
jedis.set("123","苍老师");
jedis.set("百度","知道");
// 查询所有键值对
Set<String> keys = jedis.keys("*");
// 获取name键对应的值
String name = jedis.get("name");
//打印所有key和name的值
System.out.println(keys+name);
}
}
运行结果
示例
也可以通过连接池的方式访问
JedisPool:Jedis提供的连接池技术
poolConfig:连接池配置对象
host:redis服务地址
port:redis服务端口号
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) {
this(poolConfig, host, port, 2000, (String)null, 0, (String)null);
}
封装连接参数
jedis.properties
redis.maxTotal=50
redis.maxIdel=10
redis.host=192.168.23.32
redis.port=6380
利用静态代码块初始化连接资源
静态代码块初始化资源
static{
//读取配置文件 获得参数值
ResourceBundle rb = ResourceBundle.getBundle("jedis");
host = rb.getString("jedis.host");
port = Integer.parseInt(rb.getString("jedis.port"));
maxTotal = Integer.parseInt(rb.getString("jedis.maxTotal"));
maxIdle = Integer.parseInt(rb.getString("jedis.maxIdle"));
poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxIdle(maxIdle);
jedisPool = new JedisPool(poolConfig,host,port);
}
获取连接
对外访问接口,提供jedis连接对象,连接从连接池获取
public static Jedis getJedis(){
Jedis jedis = jedisPool.getResource();
return jedis;
}
具体代码如下
redis.properties配置文件中的代码
redis.maxTotal=50
redis.maxIdel=10
redis.host=192.168.23.32
redis.port=6380
jedisUtils连接工具
package com.Utils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ResourceBundle;
public class jedisUtils {
private static String host;
private static Integer port;
private static Integer maxTotal;
private static Integer maxIdle;
private static JedisPoolConfig poolConfig;
private static JedisPool jedisPool;
static {
//读取配置文件
ResourceBundle rb = ResourceBundle.getBundle("redis");
//读取配置文件中的地址和端口号
host = rb.getString("redis.host");
port = Integer.parseInt(rb.getString("redis.port"));
//设置最大的连接池数量和初始的最大数量
maxTotal = Integer.parseInt(rb.getString("redis.maxTotal"));
maxIdle = Integer.parseInt(rb.getString("redis.maxIdel"));
//对jedis连接池进行配置
poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxIdle(maxIdle);
//jedisPool连接池来管理jedis对象
jedisPool = new JedisPool(poolConfig,host,port);
}
public static Jedis getjedis(){
//调用jedispool中getResource返回给调用者一个连接对象
Jedis jedis = jedisPool.getResource();
return jedis;
}
}
JedisTest测试类代码
package com.jedis2;
import com.Utils.jedisUtils;
import redis.clients.jedis.Jedis;
import java.util.Set;
public class JedisTest {
public static void main(String[] args) {
//直接通过类名。方法名获取到连接池对象
Jedis jedis = jedisUtils.getjedis();
//直接调用keys查看所有的key
Set<String> keys = jedis.keys("*");
//遍历数组
for (String key : keys) {
System.out.println(key);
}
}
}
运行结果
获取到了刚才存进去的所有key值