1.Redis 简介
目前互联网基本使用两种方式来进行数据的存储:关系型数据库和 NoSql 数据库。
- 关系数据库:主要用于存储格式化的数据结构,比如 MySQL、Oracle、SqlServer 等都属于关系型数据库。
- NoSql(泛指:非关系型数据库)数据库,其存储的数据都是按照键值对(Key-Value)的结构进行存储。主要服务于特定背景的专用数据库,向外提供特定的 API,而不是提供通用的 SQL 接口,所以效率更加高效,简单理解就是 NOSQL 可以不写任何 SQL 语句就能实现数据的存储与查询的数据库。
Redis 是一个开源 K-V 的数据库,属于 NoSql 数据库,并且与 Memcached 一样,为了保证效率,数据都是缓存在内存中,并基于内存操作,性能较高。它所支持存储的 value 类型相对更多,包括 string、list、set、zset 和 hash,在内存中设计了各种数据类型,让业务能够高速原子的访问这些数据结构,并且不需要关心持久存储的问题,从架构上解决了关系型数据库存储需要走一些弯路的问题。所以作为缓存应用,与其类似的 Memcached,EHCache,OSCache 等缓存器相比,Redis 的出现,很大程度补偿了 Memcached 这类 key/value 存储的不足,在高并发查询时可以对关系数据库起到很好的性能补充作用。此外与 Memcached 的最大区别在于:Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了 master-slave(主从)同步,故:Redis 支持主从同步, 数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。
redis单线程为啥操作数据速度快,redis怎么持久化数据,假如数据在持久化之前宕机怎么保证数据的安全性
1.reids是纯内存操作
2.redis全程采用hash数据结构操作数据
3.redis采用 非阻塞IO,多路复用
持久化的方式:
RDB:会按照配置的指定时间来持久化数据,当持久化数据时,redis会创建一个子线程把数据写到子线程的内存中,再有子线程把数据写到一个临时文件中 这样的缺点是不能保证数据的高可用,一旦在数据持久化以前服务器宕机并且没有触发持久化进程就会导致数据丢失
AOF:以日志的形式来记录每个写的操作,只需要追加文件,不可修改文件,因为内容是追加的所有日志文件会越来越大,针对这个问题,还有一个重写的机制,当文件大到一定程序会创建一个子线程来遍历内存中的所有数据,把每一条数据都写到临时文件中最后在替换日志文件
2.Redis 安装
-
linux:
-
创建安装路径:/usr/local/redis
-
将安装包放在 /opt/ 文件夹下
-
解压安装:tar -zxvf redis-4.0.8.tar.gz(这里时解压到当前文件夹,想要指定文件夹需要在后面加 -c )
-
将目录移动到 redis-4.0.8 目录下,编辑redis.conf文件:vi redis.conf
- shift: – 输入指令
- set nu – 显示行数
- 修改bind,原先只能进行本地访问,127.0.0.1,修改为0.0.0.0,(i键为修改文件,esc为修改完成,wq为保存并退出,q!为不保存退出)
- 修改daemonize no,原为是否允许后台启动,修改为yes
- 修改requirepass,原为注释,修改为打开注释,密码为用户设置的密码
-
启动redis:src/redis-server ./redis.conf(ps -ef | grep redis – 查看当前redis是否启动,也可以发现当前端口号为6379)
-
修改防火墙:vi /etc/sysconfig/iptables
添加一行:-A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
-
重启防火墙:service iptables restart
-
回到windows,打开 RedisDesktopManager ,创建链接,输入地址和密码,即可链接
-
3.Redis常用命令
- redis-cli:Shell 命令行下启动 Redis 客户端工具
- set(set key value):Redis 是以 key-value 的格式来存储数据的,set 命令就是设置 key 对应的 value 值(string 类型),设置成功,返回 1;失败,返回 0。
- get(get key):通过 key 值获取其对应的 value 值,若不存在,则返回 nil
- exists(exists key):判断指定的 key 是否存在,存在返回 1,不存在返回 0
- del(key):删除一个指定 key
- quit:关闭连接
- info:查看 Redis 的相关信息
- flushdb:清空当前库
- flushall:清空所有数据库
4.Redis 的设计思路
Redis 的具体使用很简单,只需要在 spring 配置文件中配置三个对象即可
redisAPI(IOC , getter , setter) => jedisPool(init , ref-jedisPoolConfig , IP , PORT)=> jedisPoolConfig(init)
首先初始化 Redis 连接池配置对象(jedisPoolConfig),然后再将该对象通过 IoC 注入到连接池对象(jedisPool)中,当连接池对象初始化时引用连接池配置对象(jedisPoolConfig),同时通过配置的 IP、端口等进行连接的实例化。最后由自定义的 redisAPI 来使用 jedisPool 对象。redisAPI 是基于 jedisPool 编写的一个数据访问对象,相当于系统中的 dao 层,比如说对数据进行一些 set、get
等操作。
5.Redis的相关配置
-
JedisPoolConfig:
Redis 连接池配置 首先进行 spring IoC 配置,在 spring 容器中注册一个 ID 为 jedisPoolConfig 的 bean,使 用 的 类 是 redis.clients.jedis.JedisPoolConfig 。
- maxActive:最大活动数。 若设置 value 为-1,则表示不限制,若 pool 已经分配了 n(设置的 value)个的 jedis 实例,则此时 pool 的状态为 exhausted(耗尽)。
- maxIdle:最大空闲数
- maxWait:表示当 borrow(引入/借调)一个 jedis 实例时,最大的等待时间,如果超过等待时间,则直接抛出 JedisConnectionException
- testOnBorrow:在 borrow 一个 jedis 实例时,是否提前进行 validate 操作;若为 true,则得到的 jedis 实例均是可用的
-
jedisPool
在 spring 容器中注册一个 ID 为 jedisPool 的 bean ,使用的类是 redis.clients.jedis.JedisPool,再将配置好的redis的连接池配置对象(jedisPoolConfig)通过 IoC 注入到连接池对象中,连接池对象初始化时引用上面的连接池配置对象,同时通过配置的 IP 和端口等进行连接的实例化。
-
redisAPI
在 spring 容器中注册一个 ID 为 redisAPI 的 bean,这个 bean 使用的类是 org.slsale.common.RedisAPI,在实例化这个 bean 的时候要通过 jedisPool 进行初始化(相当于赋值)。
-
validationToken
该工具类主要是为了根据传入的 key(Token)去 Redis 中获取相应用户信息
使用redis存取数据(代码示例-ssm)
<!--redis的配置文件-->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxActive" value="300"/>
<property name="maxIdle" value="100"/>
<property name="minIdle" value="1000"/>
<property name="testOnReturn" value="true"/>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg ref="jedisPoolConfig"/>
<constructor-arg value="192.168.11.130"/>
<constructor-arg value="6379"/>
<constructor-arg value="3000"/>
<constructor-arg value="717171"/>
</bean>
/**
* 存字符串数据
* @param key
* @param value
* @return
*/
public boolean set(String key,String value){
try {
Jedis jedis = jedisPool.getResource();//获取资源,用jedis类接收
jedis.set(key, value);//将参数存入redis
return true;//成功返回true
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 存数据 过期时间 设置时间后,过了时间会自动删除
* @param key
* @param seconds 过期时间
* @param value
* @return
*/
public boolean set(String key,int seconds,String value){
try {
Jedis jedis = jedisPool.getResource();
jedis.setex(key,seconds, value);//将参数传入redis,包含过期时间
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
- 添加判断key是否存在的方法:
/**
* 判断key是否存在
* @param key
* @return
*/
public boolean exist(String key){
try {
Jedis jedis = jedisPool.getResource();
return jedis.exists(key);//判断是否存在,返回布尔值
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
- 通过key获取数据
/**
* 通过key获取数据
* @param key
* @return
*/
public String get(String key){
String value = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
value = jedis.get(key);//通过key获取到value
} catch (Exception e) {
e.printStackTrace();
}finally {
returnResouces(jedisPool,jedis);//关闭连接池
}
return value;
}
/**
* 返还连接池
*/
public static void returnResouces(JedisPool jedisPool,Jedis jedis){
if (jedis != null){
jedisPool.returnResource(jedis);
}
}
- 查询key的过期时间
/**
* 查询当前key的过期时间,当key不存在的时候返回-2,当key存在但没有设置过期时间时返回-1,
* 否则以秒为单位返回key的剩余时间
* @param key
* @return
*/
public Long ttl(String key){
try {
Jedis jedis = jedisPool.getResource();
return jedis.ttl(key);
} catch (Exception e) {
e.printStackTrace();
}
return (long) -2;
}
- 删除数据
//删除
public void delete(String key){
try {
Jedis jedis = jedisPool.getResource();
jedis.del(key);
} catch (Exception e) {
e.printStackTrace();
}
}
springboot中多使用StringRedisTemplate,写法如下
package com.kgc.utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedisTemplate<Object, Object> redisTemplate;
@Resource(name = "stringRedisTemplate")
ValueOperations<String, String> valOpsStr;
@Resource(name = "redisTemplate")
ValueOperations<Object, Object> valOpsObj;
/**
* 根据指定key获取String
* @param key
* @return
*/
public String getStr(String key){
return valOpsStr.get(key);
}
/**
* 设置Str缓存
* @param key
* @param val
*/
public void setStr(String key, String val){
valOpsStr.set(key,val);
}
/***
* 设置Str缓存
* @param key
* @param val
* @param expire 超时时间
*/
public void setStr(String key, String val,Long expire){
valOpsStr.set(key,val,expire, TimeUnit.MINUTES);
}
/**
* 删除指定key
* @param key
*/
public void del(String key){
stringRedisTemplate.delete(key);
}
/**
* 根据指定o获取Object
* @param o
* @return
*/
public Object getObj(Object o){
return valOpsObj.get(o);
}
/**
* 设置obj缓存
* @param o1
* @param o2
*/
public void setObj(Object o1, Object o2){
valOpsObj.set(o1, o2);
}
/**
* 删除Obj缓存
* @param o
*/
public void delObj(Object o){
redisTemplate.delete(o);
}
}