目前互联网基本使用两种方式来进行数据的存储:关系型数据库和 NoSql 数据库。
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:以日志的形式来记录每个写的操作,只需要追加文件,不可修改文件,因为内容是追加的所有日志文件会越来越大,针对这个问题,还有一个重写的机制,当文件大到一定程序会创建一个子线程来遍历内存中的所有数据,把每一条数据都写到临时文件中最后在替换日志文件
创建安装路径:/usr/local/redis
将安装包放在 /opt/ 文件夹下
解压安装:tar -zxvf redis-4.0.8.tar.gz(这里时解压到当前文件夹,想要指定文件夹需要在后面加 -c )
将目录移动到 redis-4.0.8 目录下,编辑redis.conf文件:vi redis.conf
启动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 ,创建链接,输入地址和密码,即可链接
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
等操作。
Redis 连接池配置 首先进行 spring IoC 配置,在 spring 容器中注册一个 ID 为 jedisPoolConfig 的 bean,使 用 的 类 是 redis.clients.jedis.JedisPoolConfig 。
在 spring 容器中注册一个 ID 为 jedisPool 的 bean ,使用的类是 redis.clients.jedis.JedisPool,再将配置好的redis的连接池配置对象(jedisPoolConfig)通过 IoC 注入到连接池对象中,连接池对象初始化时引用上面的连接池配置对象,同时通过配置的 IP 和端口等进行连接的实例化。
在 spring 容器中注册一个 ID 为 redisAPI 的 bean,这个 bean 使用的类是 org.slsale.common.RedisAPI,在实例化这个 bean 的时候要通过 jedisPool 进行初始化(相当于赋值)。
该工具类主要是为了根据传入的 key(Token)去 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>
引入 JedisPool (@Resource):redis的核心
添加构造以及getset
添加set方法(两个):
/**
* 存字符串数据
* @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是否存在
* @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获取数据
* @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不存在的时候返回-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);
}
}