什么是Redis
Redis:REmote DIctionary Server(远程字典服务器)
是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行并支持持久化的NoSQL数据库(Not Only SQL),是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器
作用
1:内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
2:取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
3:模拟类似于HttpSession这种需要设定过期时间的功能
4:发布、订阅消息系统
5:定时器、计数器
特点
1: Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
2: Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
3:Redis支持数据的备份,即master-slave模式的数据备份
安装
- 解压后进入源码解压后的文件目录,运行 make PREFIX=/usr/app/software/redis install 具体目录按需修改
进入源码目录,里面有一份配置文件 redis.conf,然后将其拷贝到安装路径下的bin文件夹中
如:cp /usr/app/redis-3.0.0/redis.conf /usr/app/software/redis/bin
如果没有安装gcc依赖需要先安装gcc依赖: yum -y install gcc
登录Redis
启动Redis命令,以redis.conf方式启动,前提是已经复制到安装目录下了,在启动前需要先编辑该配置文件, daemonize no 改为 daemonize yes 退出保存,该配置文件中还可以配置密码端口,库的数量等,redis默认有16个库,从0到15, 启动命令是:./redis-server redis.conf此命令指示启动了服务器,可以在外部用java等操作,但是客户端内不可操作, 想要在dos命令行内操作要用redis-cli指令(redis-client客户端) ,指令为: redis-cli -a -h -p(a:密码 h:IP地址 p:端口,全都可以省略,默认是配置文件中的密码为空,地址为127.0.0.1,要是想在外部访问需要改ip地址为0.0.0.0,端口默认为6379) 要想使用DOS客户端必须先开启服务端.
Key关键字指令
常用指令:key
Keys *:指令 查看当前这个库中所有的key值
exists key: 判断某个key值是否存在 0表示不存在 1表示存在
move key 数据库的索引下标: 将某个值移除到指定的库中
Redis默认有16个库,我们可以通过修改redis配置文件redis.conf来改变库的数量
Select 下标 :可以切换不同的数据库: 下标可以从0到15之中选
expire key 秒数:设定指定的key的存活时间
ttl key:查看当前的key还有多少存活时间 -1 表示永不过期,-2表示已经过期
type key: 查看当前key的类型(key String,Object)
String类型数据指令
DOS客户端内操作可以用tab键补全
Set key value: 设置单一键值对(key值相同会覆盖原来的值,类似于map集合),当值不存在时是新增,当值已存在时是覆盖修改
Get key :获取指定key的值
Del key:删除指定名称 key
Append key 新值: 在原有的值的基础上添加新的值
Strlen key: 获取字符串的长度
(key值必须是数字)
Incr(value值自动加1) : incr key;
decr(value值自动减1) :decr key;
incrby 递增值: incrby key 每次递增数字;
decrby 递减值:decrby key 每次递减数字;
------------------------------------------------------------不常用
Getrange : GETRANGE key start end: 获取value值的一部分
Setrange :SETRANGE key 起始位置 值: 从起始位置开始替换值
Setex: SETEX key名字 存活时间 值: 设定一组值同时设定存活时间;
Setnx: SETNX key名字 值: 设置永久存活的一组值。(key值冲突无法存入值--返回值为0)
Mset: mset key 值 key 值.... 一次设定多组值,如果key值存在也会覆盖
Mget: mget key key 一次获取多个key的值
Msetnx: 一次设定多组key值,如果有key值存在无法添加完成
List类型(添加 删除内容)
Lpush: 向集合中添加内容 lpush 集合的名字 值 显示的顺序和添加的顺序相反。
Rpush: 向集合中添加内容 rpush 集合的名字 值 添加顺序就是显示顺序
Lrange 集合的名字 起始位置 结束位置(-1代表到集合的末尾)
Llen: llen 集合的名字 查看集合的长度
Lpop: lpop 集合的名称 移除集合中的第一个元素
Rpop: rop 集合的名称移除集合中的最后一个元素
lindex : 获取制定索引的值 lindex 集合的名称 索引数值
Lrem :删除指定数量的值: lrem 集合的名称 个数 值(集合中有重复值);
Set集合
Sadd:添加值 sadd 集合名称 值....
Smembers:查看值 smembers 集合名称
Scard : 集合中元素个数 scard 集合名称
Srem : 删除集合中的某个值 srem 集合名称 值;
SPOP: 随机从集合中移除一个数据 spop 集合名称
Smove: 将集合中的某个值赋给另外一个集合: SMOVE 集合1 集合2 值;
Sdiff: 差集
Sinter:交集
Sunion:并集
Hash(哈希)(key value(key value))
redis hash是一个键值对的集合, 是一个string类型的field和value的映射表,适合用于存储对象(key value(key,value))
Hset:存放一组键值对 hset key 值的名称 具体的值;(重复添加会覆盖原来的值)
Hget:获取一个值: hget key 值的名称
Hmset: 设定多组键值对 HMSET customer id 1 name zs address beijing
Hmget: 获取过个键对应的值 hmget customer id name address
Hgetall: 获取所有的数据 hgetall key值;
Hdel: 删除某个指定的key的一组value hdel customer id
Hlen: 当前的key 有几组对应的键值对
Hexists: 判断当前key中是否有指定名称的键值对: hexists customer id;
Hkeys:获取所有的key
Hvals: 获取所有的值
Hincrby: 增加指定步长的数据 hincrby customer age 2;
Hincrbyfloat: 在原有的基础上增加指定的小数。 hincrbyfloat customer course 0.5
Hsetnx: 如果key存在不能添加到集合中,如果key不存在则添加到集合中。
Zset
zset(sorted set 有序集合) 是string类型的有序集合,也不可重复
sorted set中的每个元素都需要指定一个分数,根据分数对元素进行升序排序,如果多个元素有相同的分数,则以字典序进行升序排序,sorted set 因此非常适合实现排名
Zadd:创建集合并设定标准 zadd zset01 60 v1 70 v2 80 v3 90 v4 100 v5(等级划分的数据)
游戏 : 青铜 白银 黄金。。。
普通 vip
Zrange: 查询所有的标准 ZRANGE zset01 0 -1 , ZRANGE zset01 0 -1 withscores
ZRANGEBYSCORE :根据分数查询内容
ZRANGEBYSCORE zset01 60 90 (注意如果前面添加”(” 表示不包含节点的意思) withscores limit 起始位置 数量.
Zrem :删除元素 zrem 集合 某score下对应的value值。ZREM zset01 v5
Zcard: 统计有几个键值对 zcard 集合
Zcount: zcount 集合 数值1 数值2 统计区间的值
Zrank : 统计对应的下标 zrank 集合名 values
Zscore : zscore 集合名 values 获取对应的分数
Java连接redis
1.首先要设置redis.conf配置文件中的IP地址为0.0.0.0
2.放行6379端口: firewall-cmd --zone=public --add-port=6379/tcp --permanent 重启防火墙,systemctl restart firewalld.service,接着重启Redis服务 : redis-cli shutdown 然后 redis-server redis.conf
3.如果需要设置密码,java中也需要相应的设置连接密码
操作程序分为三步: 创建连接 -- 执行操作 -- 释放资源
1.普通连接方法
package com.offcn.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.offcn.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
public class Test1 {
@Test//保存操作
public void test1(){
//建立连接,创建jedis对象:Redis所在服务器ip和reids的端口号
Jedis jedis = new Jedis("192.168.146.128",6379);
//jedis设置登录密码,可以不写
// jedis.auth("设置密码");
//实现保存操作
String key = "user";
String value = "{\"uname\":\"zhangfei\",\"upwd\":\"123\"}";
jedis.set(key,value);
//释放资源
jedis.close();
}
@Test//获取操作
public void test2() throws IOException {
//建立连接
Jedis jedis = new Jedis("192.168.146.128",6379);
//获取数据
String user = jedis.get("user");
System.out.println(user);
ObjectMapper objectMapper = new ObjectMapper();
User user1 = objectMapper.readValue(user, User.class);
System.out.println(user1);
//释放资源
jedis.close();
}
@Test//使用jedis连接池保存数据
public void test3() throws JsonProcessingException {
//创建jedis连接池
JedisPool jedisPool = new JedisPool("192.168.146.128",6379);
//从池子中获取连接
Jedis resource = jedisPool.getResource();
//完成保存操作
User user = new User();
user.setUname("关羽");
user.setUpwd("123");
ObjectMapper objectMapper = new ObjectMapper();
String s1 = objectMapper.writeValueAsString(user);
UUID uuid = UUID.randomUUID();
String s2 = uuid.toString().substring(0, 4);
resource.set(s2,s1);
//释放资源
resource.close();
}
@Test//使用jedis连接池获取数据
public void test4(){
//创建jedis连接池
JedisPool jedisPool = new JedisPool("192.168.146.128",6379);
//从池子中获取连接
Jedis resource = jedisPool.getResource();
//获取数据
String s = resource.get("e31e");
System.out.println(s);
//释放资源
resource.close();
}
@Test//模拟一个业务层的方法
public void test5(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
JedisPool pool = (JedisPool) context.getBean("pool");
Jedis resource = pool.getResource();
System.out.println(resource);
}
}
2.连接池方式
package com.offcn.test;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.offcn.bean.User;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.io.IOException;
import java.util.Set;
public class Test2 {
@Test//向redis缓存中保存数据
public void test1() throws JsonProcessingException {
//redis类似于连接数据库的步骤,其实redis就是一个数据库,他把数据保存到内存中
//建立连接
Jedis jedis = new Jedis("192.168.146.128",6379);
//创建我们要保存的数据
User user = new User();
user.setUname("熊大");
user.setUpwd("123");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(user);
//执行保存操作
jedis.set("key1", s);
//释放资源
jedis.close();
}
@Test//获取jedis中的数据
public void test2() throws IOException {
//创建连接
Jedis jedis = new Jedis("192.168.146.128",6379);
//读取数据
String value1 = jedis.get("key1");
ObjectMapper objectMapper = new ObjectMapper();
User user = objectMapper.readValue(value1, User.class);
System.out.println(user.getUname()+"=="+user.getUpwd());
//获取所有的key
Set<String> keys = jedis.keys("*");
for(String s:keys){
System.out.println(s);
}
//释放资源
jedis.close();
}
@Test//使用连接池保存数据到redis中
public void test3() throws JsonProcessingException {
//获取连接池
JedisPool pool = new JedisPool("192.168.146.128",6379);
//从连接池中获取jedis连接
Jedis resource = pool.getResource();
//创建资源并保存
User user = new User();
user.setUname("熊二");
user.setUpwd("456");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(user);
//执行保存操作
resource.set("key2",s);
//释放资源
resource.close();
}
@Test//使用连接池获取jedis中的值
public void test4() throws IOException {
//创建连接池
JedisPool pool = new JedisPool("192.168.146.128",6379);
//从连接池中获取连接
Jedis resource = pool.getResource();
//执行获取操作
String value2 = resource.get("key2");
//用jackson转化为对象
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(value2, User.class);
System.out.println(user);
//释放资源
resource.close();
}
}
Spring整合Redis
在业务层,新增一个Redis框架,作用是用来保存业务数据,或者从Redis库中获取业务数据,Redis是内存数据库,MySQL/Oracle是非内存数据库;所以如果把常用的不经常变化的业务数据保存到Redis库,那么就可以在业务层当调用这些数据的时候,不需要向MySQL等数据库发送SQL实现查询,只需要从Redis中直接获取即可,这样就可以提高效率
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--spring整合Redis-->
<!--配置jedis池的参数-->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="10"/>
<!-- 空闲连接数 -->
<property name="maxIdle" value="2"/>
<!-- 设置链接池的连接耗尽时,是否等待 -->
<property name="blockWhenExhausted" value="true"/>
<!-- 最大等待时间 -->
<property name="maxWaitMillis" value="30000"/>
<!-- 获取到连接时,是否检查链接的有效性 -->
<property name="testOnBorrow" value="true"/>
</bean>
<!--由参数把池造出来-->
<bean id="pool" class="redis.clients.jedis.JedisPool">
<!--参数注入-->
<constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
<!--ip注入-->
<constructor-arg name="host" value="192.168.146.132"></constructor-arg>
<!--端口注入-->
<constructor-arg name="port" value="6379"></constructor-arg>
</bean>
</beans>
模拟一个业务层方法
package com.offcn.test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.offcn.bean.User;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.UUID;
public class Test1 {
@Test
public void test5(){
//此单元模拟一个业务层的方法
ApplicationContext context = new ClassPathXmlApplicationContext("spring-redis.xml");
JedisPool pool = (JedisPool) context.getBean("pool");
Jedis resource = pool.getResource();
System.out.println(resource);
}
}
Spring整合mybatis,实现自定义二级缓存
Mybatis二级缓存原理
Mybatis的二级缓存是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。
在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则二级缓存清空。
二级缓存是mapper级别的。Mybatis默认是没有开启二级缓存。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存。