Redis
NOSQL概念
Redis是一款高性能的NOSQL系列的非关系型数据库
非关系型数据库:
- 数据之间没有关系
- 数据是以键值对的形式存储的
- 数据存储在内存中,访问速度相较于关系型数据库更快
非关系型数据库使用场景:经常查询一些不太发生变化的数据,这种情况通常通过缓存思想来解决问题
先从缓存中获取要查询的数据,如果缓存中有数据就直接返回缓存中的数据。如果缓存中没有数据,就进入数据库中查询数据,将查询到的数据放进缓存中,然后返回数据。下次进行相同的查询的时候,就不需要与数据库进行交互了,直接从缓存中读取数据,速度更加快,提高了效率。
在这种情况下,由于缓存存储的数据也是越来越多的,简单的使用本地的map集合进行数据的存储时不够的,就需要使用非关系型数据库进行存储。
在实际的开发中就会将redis数据库用来存储缓存数据,当缓存使用
关系型数据库
-
数据之间有关系
-
数据存储在硬盘上
-
操作关系型数据库是非常耗时的
NOSQL和关系型数据库的比较
优点
- NOSQL数据库简单易于部署, 基本都是开源软件,不需要像使用oracle那样花费大量的成本去购买,价格便宜
- NOSQL将数据存储在缓存中,关系型数据库将数据存储在硬盘中,查询速度自然是菲关系型数据库更快
- NQSQL存储格式是键值对形式、文档形式,图片形式等等,所以可以基础数据类型数据以及对象或是集合等等各种格式,而关系型数据库只能存储基础数据类型数据
- 关系型数据库有类似JOIN这样的多表联查机制导致扩展性不好
缺点
- 不提供对sql的支持
- 不提供关系型数据库对事务的处理机制
在实际的开发中,关系型数据库和非关系型数据库时互补的。一般是将数据存储在关系型数据库中,然后在非关系型数据库中进行数据的备份
主流的NOSQL产品
-
键值对存储数据
相关产品:Redis、Voldmort、Berkrlry DB
应用场景:内容缓存,主要用于处理大量数据的高访问负荷
数据模型:键值对
优势:快速查询、
劣势:数据库结构化差
-
列存储数据库
相关产品:HBase,Riak
应用场景:分布式的文件系统
数据模型:以列簇式存储,将同一列数据放在一起
优势:查找速度快,可扩展性强,更容易进行分布式扩展
劣势:功能局限
-
文档型数据库
相关产品:CouchDB、MongoDB
应用场景:web应用
数据模型:一系列键值对
优势:数据结构要求不严格
劣势:查询性能不高,缺乏统一的查询语法
-
图形数据库
相关产品Neo4J,InfoGrid,Infinite Graph
应用场景:社交网络
数据模型:图结构
优势:利用图结构相关算法
Redis
支持的数据类型:
- 字符串类型:string
- 哈希类型:hash
- 列表类型:list
- 集合类型:set
- 有序集合类型:sortedset
应用场景:
- 缓存
- 聊天室的在线好友列表
- 任务队列
- 应用排行榜
- 网站访问统计
- 数据过期处理
- 分布式架构中的session分离
配置与安装
- 官网 https://redis.io
- 将文件解压后就可以直接使用
- redis.windows.config 配置文件
- redis-cli.exe 客户端:服务端启动服务之后在客户端进行操作即可
- redis-server.exe 服务端:服务器端双击文件直接启动
命令操作
Redis数据结构:
- 以键值对存储数据,即 key-value,其中,key 均为字符串,value有五种
- string
- hash
- list
- hash
- sortedset
不同数据结构的命令操作:
string
- 存储:set key value
- 获取:get key
- 删除:del key
Hash
- 存储:hset key field value
- 获取:hget key field
- 删除:hdel key field
- 获取一个key对应的所有值:hgetall key
List
list可以添加数据到列表的头部或是列表的尾部
-
从列表头部添加数据:lpush key value
-
从列表尾部添加数据:rpush key value
-
范围获取:lrnage ket start end
其中.list中数据元素下标从0开始,最后一个元素的下标可以是-1,同理,倒数第二个元素的下标就可以是-2
-
删除:lpop key
这里的删除和栈中删除数据类似,使用pop弹出,这里删除的是list头部的第一个元素
-
删除:rpop key
删除list尾部的第一个元素
set
集合中不允许存放重复数据
- 存储:sadd key value
- 获取:smembers key
- 删除set集合中的某个元素:srem key value
sortedset
- 存储:zadd key score value
- 获取:zrange key start end
- 删除:zren key value
持久化
redis是一个内存服务器,当服务重启之后,之前的数据就会丢失。为解决这种问题,可以将内存中的数据持久化,将内存中的数据存储到硬盘中,再次重启服务的时候,将数据读取到内存中。这种行为称为redis的持久化。
redis中有两种持久化的方法:
-
RDB:默认方案,不需要进行相关的配置,默认使用这种持久化方案。原理是在一定的间隔时间中检测key的变化,然后持久化数据
-
编辑redis.windows.conf文件
如何编辑配置文件
这是配置文件中的一段信息,分别是
- 900秒至少有1个key发生变动就持久化数据
- 300秒至少有10个key发生变动就持久化数据
- 60秒至少有10000个key发生变动就持久化数据
根据实际开发需求进行适当改变就行
使用 key * 命令是用来查看所有的持久化的数据的
-
-
AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作之后,持久化数据
-
同样要编辑redis.windows.conf文件
找到
-
将appendonly的值设置为yes,默认的no 表示默认AOF机制是关闭的,要将其打开。
其他三个配置属性
分别是,每一次都进行持久化操作、每间隔一秒进行一次持久化操作、不进行持久化。根据实际应用场景进行选择。
AOF进行持久化后就会生成一个.aof后缀的文件
Jedis
一款java操作redis数据库的工具,使用起来相较于JDBC比较简单
步骤:
-
导入jar包
-
获取连接
-
执行操作
-
关闭连接
演示:
import org.junit.Test;
import redis.clients.jedis.Jedis;
public class JedisTest01 {
@Test
public void test01() {
//获取连接
Jedis jedis = new Jedis("localhost",6379);
//操作'
jedis.set("username","justin");
//关闭连接
jedis.close();
}
}
Java中的redis操作
@Test
public void StringTest(){
Jedis jedis=new Jedis("localhost",6379);
jedis.set("username","justin bibber");
jedis.set("passewrd","123456");
String username = jedis.get("username");
System.out.println(username);
//一个能够在指定时间自动删除记录的方法
jedis.setex("activecode",20,"actived");
//将该键值对存入redis内存,20秒后删除,这个思想可以应用到时效性激活码的设计上,并且是在内存中的,使用比较方便
}
@Test
public void HashTest(){
Jedis jedis=new Jedis("localhost",6379);
jedis.hset("user","username","justin bibber");
jedis.hset("user","password","123456");
jedis.hset("user","sex","male");
String name=jedis.hget("user","username");
String password=jedis.hget("user","password");
System.out.println(name);
System.out.println(password);
Map<String, String> user = jedis.hgetAll("user");
Set<String> key=user.keySet(); //返回映射中所有ket组成的Set
for (String s : key) {
String value=user.get(s); //拿到set对应的value
System.out.println(s+":"+value);
}
jedis.close();
}
@Test
public void listTest(){
Jedis jedis=new Jedis("localhost",6379);
jedis.lpush("user","a");
jedis.rpush("user","b");
jedis.lpush("user","c");
//范围获取
List<String> list=jedis.lrange("user",0,-1);
for (String s : list) {
System.out.println(s);
}
String user = jedis.lpop("user");
System.out.println(user);
jedis.close();
}
@Test
public void setTest(){
Jedis jedis=new Jedis("localhost",6379);
jedis.sadd("myset","a");
jedis.sadd("myset","b");
jedis.sadd("myset","c");
Set<String> set=jedis.smembers("myset");
for (String s : set) {
System.out.println(s);
}
}
@Test
public void SortedsetTest(){
Jedis jedis=new Jedis("localhost",6379);
jedis.zadd("sortedset",17,"justin");
jedis.zadd("sortedset",99,"alan");
jedis.zadd("sortedset",67,"fox");
//默认正排序输出
Set<String> sortedset = jedis.zrange("sortedset", 0, -1);
for (String s : sortedset) {
System.out.println(s);
}
Jedis连接池
概念和JDBC中的连接池的概念是一样的,就是在一个池子中创建多个初始化连接,以便于提高效率,对于连接有了更好的复用和管理。Jedis连接池不需要依赖第三方的提供,Jedis自带连接池——JedisPool。
使用方法:
- 创建JedisPool连接池对象
- 调用方法getResources() 方法获取连接
- 归还连接
public void test01(){
//创建连接池对象
JedisPool jedisPool=new JedisPool();
//获取连接
Jedis jedis=jedisPool.getResource();
//归还连接
jedis.close();
}
注意:
JedisPool构造参数中默认无参的时候对应的就是默认的配置文件,想要对配置进行修改并使用修改后的连接池,就要使用有参构造方法。
与JDBC连接池不同的是,Jedis连接池中的配置并不是在配置文件中修改的,而是要创建一个,JedisPoolConfig对象,使用该对象中的set方法设置参数。
具体步骤就是
-
创建JedisPoolonfig对象
-
调用对象的set方法修改参数
一旦设置了自定义的配置之后,jedispool()中传递的参数就是该配置对象的名字。
相关的set方法对应的配置的目的:
-
setMaxTotal 设置最大活动对象数
-
setMaxWaitMillis 池内没有返回对象的时候的最大等待时间
实现一个连接池工具类
实现一个工具类,将配置信息封装在配置文件中并且通过工具类的加载,直接获取连接池中的连接
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class JedisUtil {
private static JedisPool jedisPool;
//使用静态代码块,在类加载的时候读取资源文件
static {
InputStream resourceAsStream = JedisUtil.class.getClassLoader().getResourceAsStream("jedis.properties");
Properties properties=new Properties();
try {
properties.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}
JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(Integer.parseInt(properties.getProperty("maxTotal"))); //将配置文件中的字符串转换成数字
jedisPoolConfig.setMaxIdle(Integer.parseInt(properties.getProperty("maxIdle")));
//初始化连接池
jedisPool=new JedisPool(jedisPoolConfig,properties.getProperty("host"),Integer.parseInt(properties.getProperty("port")));
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}