在使用关系型数据库的时候如果发生海量的用户请求对表进行读取,修改等等会导致关系型数据库的崩溃,而且读取速率低下应对高并发的情况处理能力不足,数据关系复杂,扩展性差,不便于大规模集群,这时就有了非关系型数据库 非关系型数据库Nosql 降低了磁盘的IO流次数,通过内存存储的方式 去除了数据间的关系,越是简单越好,通过不存储数据关系只存储数据的形式 可扩容,可伸缩 灵活的数据模型 大数据量下高性能 其中最常用的就是Redis
直接在liunx中解压 创建conf和data目录用来存放配置文件和日志文件 在conf中修改配置文件 这里吧端口改成了6380 IP地址更改成0.0.0.0方便后面访问日志文件存放在打他目录下文件名为logs-6380.log 配置完成以后在src下启动 通过配置文件启动 遇到报错,说是无法读取logs-6380.log 权限不够,这里可以去更改配置文件权限,也可以把自己用户变成管理员进行操作 在更改完管理员用户后成功运行 然后可以查看是否存在6380的端口服务
端口正常运行就可以进入redis服务了 这就说明成功启动了。
redis 数据存储格式
redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串Redis 数据类型(5种常用) ⚫ string ⚫ hash ⚫ list ⚫ set ⚫ sorted_set/zset(应用性较低)
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如果是对对象进行一个存储用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 类型数据操作注意事项
1. list中保存的数据都是string类型的,数据总容量是有限的,最多2^32- 1元素 (4294967295)。 2. list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作 3. 获取全部数据操作结束索引设置为-1 4. list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加载应用场景 企业运营过程中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出? 可以用list来解决
依赖list的数据具有顺序的特征对信息进行管理使用队列模型解决多路信息汇总合并的问题使用栈模型解决最新消息的问题新的存储需求:存储大量的数据,在查询方面提供更高的效率 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询 set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的 set 类型数据的基本操作 set 类型数据操作的注意事项
set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
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=6380jedisUtils连接工具
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值