目录
1. 使用redis做缓存
1.1. 什么是redis
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如
下:
字符串类型
散列类型
列表类型
集合类型
有序集合类型。
1.2. redis的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)
分布式集群架构中的session分离。
聊天室的在线好友列表。
任务队列。(秒杀、抢购、12306等等)
应用排行榜。
网站访问统计。
数据过期处理(可以精确到毫秒)
1.3. 安装redis
版本说明
本教程使用redis3.0版本。3.0版本主要增加了redis集群功能。
-
安装的前提条件:
需要安装gcc:
yum install gcc-c++
- 下载redis的源码包,把源码包上传到linux服务器
- 解压源码包
tar -zxvf redis-3.0.0.tar.gz
- 跳转到安装包目录
cd redis-3.0.0
- Make install PREFIX=/usr/local/redis
PREFIX=/usr/local/redis指定安装的路径
1.4. 启动redis
1.4.1 前端启动模式
/usr/local/redis/bin
./redis-server
默认是前端启动模式,端口是6379
前段启动需要占用窗口
1.4.2 后端启动
从redis的源码目录中复制redis.conf到redis的安装目录。
cp redis.conf /usr/local/redis/bin/
1)修改配置文件
==cd /usr/local/redis/bin/==进入到bin目录
vim redis.conf 修改redis.conf文件
将no改成yes
./redis-server redis.conf 后端启动
ps aux|grep redis 查看进程
1.5. 常用数据类型
String
Hash
List
Set
SortedSet
2. Redis集群的搭建
2.1. Redis集群相关概念
2.1.1. redis-cluster架构图
redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
Key:a
计算a的hash值,例如值为100,100这个槽在server1上,所以a应该放到server1.
Key:hello
Hash值:10032,此槽在server2上。Hell可以应该存在server2.
2.1.2. redis-cluster投票:容错
(1)领着投票过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉.
(2):什么时候整个集群不可用(cluster_state:fail)?
a:如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,也可以理解成集群的slot映射[0-16383]不完成时进入fail状态. ps : redis-3.0.0.rc1加入cluster-require-full-coverage参数,默认关闭,打开集群兼容部分失败.
b:如果集群超过半数以上master挂掉,无论是否有slave集群进入fail状态.
ps:当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
2.2. 我们的集群结构
集群中有三个节点的集群,每个节点有一主一备。需要6台虚拟机。
搭建一个伪分布式的集群,使用6个redis实例来模拟。
2.3. 搭建集群需要的环境
搭建集群需要使用到官方提供的ruby脚本。
需要安装ruby的环境。
2.3.1. 安装ruby
yum install ruby
yum install rubygems
2.3.2. redis集群管理工具redis-trib.rb
redis的解压目录下的src
cd /export/decompression/redis-3.0.0/src/
ll *.rb
上传脚本需要的ruby包:
安装ruby的包:gem install redis-3.0.0.gem
2.4. 集群的搭建
2.4.1. 在/usr/local/ 下创建redis-cluster目录
cd /usr/local/
mkdir redis-cluster
2.4.2. 复制bin目录到redis-cluster目录下并改名为redis01
cd redis
cp -r bin/ …/redis-cluster/redis01
cd …/redis-cluster/
cd redis01/
2.4.3 删除dump.rdb
rm -f dump.rdb
2.4.4 修改Vim redis.conf
创建6个redis实例,端口号从7001~7006
修改redis的配置文件
vim redis.conf
修改端口号
打开cluster-enable前面的注释。
查找:/cluster
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLa1k0oB-1624752354044)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20210518091018530.png)]
2.4.5. 集群
把创建集群的ruby脚本复制到redis-cluster目录下。
cd /usr/local/redis-cluster/
cp -r redis01/ redis02
修改端口号7001~7006
将redis解压目录下的src里面的redis-trib.rb复制到/usr/local/redis-cluster/
redis的解压目录下的src
==cd /export/decompression/redis-3.0.0/src/==redis解压目录
ll *.rb查看redis-trib.rb文件
cp *.rb /usr/local/redis-cluster/ 复制文件
cd /usr/local/redis-cluster/
ll 查看文件
启动6个redis实例
创建startall.sh文件
vim startall.sh
cd redis01
./redis-server redis.conf
cd ..
cd redis02
./redis-server redis.conf
cd ..
cd redis03
./redis-server redis.conf
cd ..
cd redis04
./redis-server redis.conf
cd ..
cd redis05
./redis-server redis.conf
cd ..
cd redis06
./redis-server redis.conf
保存,退出
执行该文件==./startall.sh==
如果权限不够
chmod 777 ./startall.sh
查看ps aux|grep redis
创建集群。
./redis-trib.rb create --replicas 1 192.168.10.140:7001 192.168.10.140:7002 192.168.10.140:7003 192.168.10.140:7004 192.168.10.140:7005 192.168.10.140:7006
2.5. 测试集群
redis01/redis-cli -h 192.168.37.162 -p 7002 -c
-c代表连接集群
2.6. 关闭redis
2.6.1. 方式一
cd /usr/local/redis/bin/
./redis-cli
报错:Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>
原因:服务端未启动
./redis-server redis.conf
./redis-cli
2.6.2. 方式二
cd /usr/local/redis-cluster/
redis01/redis-cli -p 7001 shutdown 关闭
ps aux|grep redis 查看
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V3zOTakC-1624752354078)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20210518095002003.png)]
2.6.3. 方式三
vim shutdown.sh
redis01/redis-cli -p 7001 shutdown
redis01/redis-cli -p 7002 shutdown
redis01/redis-cli -p 7003 shutdown
redis01/redis-cli -p 7004 shutdown
redis01/redis-cli -p 7005 shutdown
redis01/redis-cli -p 7006 shutdown
权限:chmod +x shutdown.sh
./shutdown.sh 关闭
2.7. Redis客户端
2.7.1. Redis-cli
自带客户端。使用最多的。
2.7.2. 图形化界面客户端
支持单机版,不支持集群
双击运行安装
安装成功
连接
报错:
解决方案:
开放6379端口
vi /etc/sysconfig/iptables
systemctl restart iptables.service 重启防火墙
2.7.3. Jedis客户端
2.7.3.1 单机版
需要把jedis的jar包添加到工程中,如果是maven需要添加jar包的坐标。
【taotao-parent】 -【pom.xml】
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
【/taotao-rest/】—【pom.xml】
将redis客户端复制过来,并把版本号删掉。
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2.7.3.2 单机版测试
JedisTest.java
【/taotao-rest】—【/src/test/java/】—【com/taotao/rest/test/】—【JedisTest.java】
package com.taotao.rest.test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.util.HashSet;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JedisTest {
/**
* 单机版
*/
@Test
public void testJedisSingle() {
// 创建一个jedis的对象。
Jedis jedis = new Jedis("192.168.10.140", 6379);
// 调用jedis对象的方法,方法名称和redis的命令一致。
jedis.set("key1", "jedis test");
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis。
jedis.close();
}
/**
* 使用连接池
*/
@Test
public void testJedisPool() {
// 创建jedis连接池
JedisPool pool = new JedisPool("192.168.10.140", 6379);
// 从连接池中获得Jedis对象
Jedis jedis = pool.getResource();
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis对象
jedis.close();
pool.close();
}
}
2.7.3.3 集群版
JedisTest.java
【/taotao-rest】—【/src/test/java/】—【com/taotao/rest/test/】—【JedisTest.java】
package com.taotao.rest.test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.util.HashSet;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JedisTest {
/**
* 单机版
*/
@Test
public void testJedisSingle() {
// 创建一个jedis的对象。
Jedis jedis = new Jedis("192.168.10.140", 6379);
// 调用jedis对象的方法,方法名称和redis的命令一致。
jedis.set("key1", "jedis test");
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis。
jedis.close();
}
/**
* 使用连接池
*/
@Test
public void testJedisPool() {
// 创建jedis连接池
JedisPool pool = new JedisPool("192.168.10.140", 6379);
// 从连接池中获得Jedis对象
Jedis jedis = pool.getResource();
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis对象
jedis.close();
pool.close();
}
/**集群版
*
*/
@Test
public void testJedisCluster() {
HashSet<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.10.140", 7001));
nodes.add(new HostAndPort("192.168.10.140", 7002));
nodes.add(new HostAndPort("192.168.10.140", 7003));
nodes.add(new HostAndPort("192.168.10.140", 7004));
nodes.add(new HostAndPort("192.168.10.140", 7005));
nodes.add(new HostAndPort("192.168.10.140", 7006));
JedisCluster cluster = new JedisCluster(nodes);
cluster.set("key1", "1000");
String string = cluster.get("key1");
System.out.println(string);
cluster.close();
}
}
虚拟机
cd /usr/local/redis-cluster/
redis01/redis-cli -p 7001 -c
get key1
集群版不需要使用连接池,自带
3. 业务逻辑中添加缓存
需要在taotao-rest工程中添加缓存。
3.1. jedis整合spring
3.1.1. 单机版整合
applicationContext-jedis.xml
【/taotao-rest】—【/src/main/resources】—【/spring/】—【applicationContext-jedis.xml】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 连接池配置 -->
<bean id="jedisPoolConfig"
class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<!-- jedis客户端单机版 -->
<!-- -->
<bean id="redisClient" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
<constructor-arg name="poolConfig"
ref="jedisPoolConfig"></constructor-arg>
</bean>
</beans>
3.1.2 测试
JedisTest.java
【/taotao-rest】—【/src/test/java/】—【com/taotao/rest/test/】—【JedisTest.java】
package com.taotao.rest.test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.util.HashSet;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JedisTest {
/**
* 单机版
*/
@Test
public void testJedisSingle() {
// 创建一个jedis的对象。
Jedis jedis = new Jedis("192.168.10.140", 6379);
// 调用jedis对象的方法,方法名称和redis的命令一致。
jedis.set("key1", "jedis test");
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis。
jedis.close();
}
/**
* 使用连接池
*/
@Test
public void testJedisPool() {
// 创建jedis连接池
JedisPool pool = new JedisPool("192.168.10.140", 6379);
// 从连接池中获得Jedis对象
Jedis jedis = pool.getResource();
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis对象
jedis.close();
pool.close();
}
/**集群版
*
*/
@Test
public void testJedisCluster() {
HashSet<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.10.140", 7001));
nodes.add(new HostAndPort("192.168.10.140", 7002));
nodes.add(new HostAndPort("192.168.10.140", 7003));
nodes.add(new HostAndPort("192.168.10.140", 7004));
nodes.add(new HostAndPort("192.168.10.140", 7005));
nodes.add(new HostAndPort("192.168.10.140", 7006));
JedisCluster cluster = new JedisCluster(nodes);
cluster.set("key1", "1000");
String string = cluster.get("key1");
System.out.println(string);
cluster.close();
}
/**业务逻辑中添加缓存
* 单机版测试
*/
@Test
public void testSpringJedisSingle() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
JedisPool pool = (JedisPool) applicationContext.getBean("redisClient");
Jedis jedis = pool.getResource();
String string = jedis.get("key1");
System.out.println(string);
jedis.close();
pool.close();
}
}
3.1.2. 集群版整合
applicationContext-jedis.xml
【/taotao-rest】—【/src/main/resources】—【/spring/】—【applicationContext-jedis.xml】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 连接池配置 -->
<bean id="jedisPoolConfig"
class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<!-- jedis集群版配置 -->
<bean id="redisClient" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
</beans>
JedisTest.java
【/taotao-rest】—【/src/test/java/】—【com/taotao/rest/test/】—【JedisTest.java】
package com.taotao.rest.test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import java.util.HashSet;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JedisTest {
/**
* 单机版
*/
@Test
public void testJedisSingle() {
// 创建一个jedis的对象。
Jedis jedis = new Jedis("192.168.10.140", 6379);
// 调用jedis对象的方法,方法名称和redis的命令一致。
jedis.set("key1", "jedis test");
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis。
jedis.close();
}
/**
* 使用连接池
*/
@Test
public void testJedisPool() {
// 创建jedis连接池
JedisPool pool = new JedisPool("192.168.10.140", 6379);
// 从连接池中获得Jedis对象
Jedis jedis = pool.getResource();
String string = jedis.get("key1");
System.out.println(string);
// 关闭jedis对象
jedis.close();
pool.close();
}
/**集群版
*
*/
@Test
public void testJedisCluster() {
HashSet<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.10.140", 7001));
nodes.add(new HostAndPort("192.168.10.140", 7002));
nodes.add(new HostAndPort("192.168.10.140", 7003));
nodes.add(new HostAndPort("192.168.10.140", 7004));
nodes.add(new HostAndPort("192.168.10.140", 7005));
nodes.add(new HostAndPort("192.168.10.140", 7006));
JedisCluster cluster = new JedisCluster(nodes);
cluster.set("key1", "1000");
String string = cluster.get("key1");
System.out.println(string);
cluster.close();
}
/**业务逻辑中添加缓存
* 单机版测试
*/
@Test
public void testSpringJedisSingle() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
JedisPool pool = (JedisPool) applicationContext.getBean("redisClient");
Jedis jedis = pool.getResource();
String string = jedis.get("key1");
System.out.println(string);
jedis.close();
pool.close();
}
/**业务逻辑中添加缓存
* 集群版测试
*/
@Test
public void testSpringJedisCluster() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
JedisCluster jedisCluster = (JedisCluster) applicationContext.getBean("redisClient");
String string = jedisCluster.get("key1");
System.out.println(string);
jedisCluster.close();
}
}
3.2. 添加jedis dao
3.2.1. 单机版
JedisClient.java接口
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/dao/】—【JedisClient.java】
package com.taotao.rest.dao;
/**
* 业务逻辑中添加缓存
* 添加jedis dao
* @author Lenovo
*
*/
public interface JedisClient {
String get(String key);
String set(String key, String value);
String hget(String hkey, String key);
long hset(String hkey, String key, String value);
long incr(String key);
long expire(String key, int second);
long ttl(String key);
long del(String key);
long hdel(String hkey, String key);
}
JedisClientSingle.java 实现类
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/dao/impl/】—【JedisClientSingle.java】
package com.taotao.rest.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.taotao.rest.dao.JedisClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* 业务逻辑中添加缓存
* 添加jedis dao
* 单机版
* @author Lenovo
*
*/
public class JedisClientSingle implements JedisClient{
@Autowired
private JedisPool jedisPool;
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String string = jedis.get(key);
jedis.close();
return string;
}
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String string = jedis.set(key, value);
jedis.close();
return string;
}
@Override
public String hget(String hkey, String key) {
Jedis jedis = jedisPool.getResource();
String string = jedis.hget(hkey, key);
jedis.close();
return string;
}
@Override
public long hset(String hkey, String key, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(hkey, key, value);
jedis.close();
return result;
}
@Override
public long incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public long expire(String key, int second) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, second);
jedis.close();
return result;
}
@Override
public long ttl(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}
@Override
public long del(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
}
@Override
public long hdel(String hkey, String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(hkey, key);
jedis.close();
return result;
}
}
Spring配置文件applicationContext-jedis.xml
【/taotao-rest】—【/src/main/resources】—【/spring/】—【applicationContext-jedis.xml】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 连接池配置 -->
<bean id="jedisPoolConfig"
class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<!-- jedis客户端单机版 -->
<!-- -->
<bean id="redisClient" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
<constructor-arg name="poolConfig"
ref="jedisPoolConfig"></constructor-arg>
</bean>
<!-- jedis集群版配置 -->
<!--
<bean id="redisClient" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
-->
<!-- 添加jedis dao 单机版-->
<bean id="jedisClient" class="com.taotao.rest.dao.impl.JedisClientSingle"></bean>
</beans>
3.2.2. 集群版
JedisClientCluster.java
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/dao/impl/】—【JedisClientCluster.java】
package com.taotao.rest.dao.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.taotao.rest.dao.JedisClient;
import redis.clients.jedis.JedisCluster;
/**
* 业务逻辑中添加缓存
* 添加jedis dao
* 集群版
* @author Lenovo
*
*/
public class JedisClientCluster implements JedisClient {
@Autowired
private JedisCluster jedisCluster;
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String hget(String hkey, String key) {
return jedisCluster.hget(hkey, key);
}
@Override
public long hset(String hkey, String key, String value) {
return jedisCluster.hset(hkey, key, value);
}
@Override
public long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public long expire(String key, int second) {
return jedisCluster.expire(key, second);
}
@Override
public long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public long del(String key) {
return jedisCluster.del(key);
}
@Override
public long hdel(String hkey, String key) {
return jedisCluster.hdel(hkey, key);
}
}
Spring配置文件applicationContext-jedis.xml
【/taotao-rest】—【/src/main/resources】—【/spring/】—【applicationContext-jedis.xml】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 连接池配置 -->
<bean id="jedisPoolConfig"
class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<!-- jedis客户端单机版 -->
<!-- -->
<bean id="redisClient" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="6379"></constructor-arg>
<constructor-arg name="poolConfig"
ref="jedisPoolConfig"></constructor-arg>
</bean>
<!-- 添加jedis dao单机版 -->
<bean id="jedisClient" class="com.taotao.rest.dao.impl.JedisClientSingle"></bean>
<!-- jedis集群版配置 -->
<!--
<bean id="redisClient" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.10.140"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
-->
<!-- 添加jedis dao集群版 -->
<bean id="jedisClientCluster" class="com.taotao.rest.dao.impl.JedisClientCluster"></bean>
</beans>
3.3. 把缓存添加到业务逻辑
注意:缓存的添加不能影响正常的业务逻辑。
ContentServiceImpl.java
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/service/impl/】—【ContentServiceImpl.java】
package com.taotao.rest.service.impl;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.taotao.common.utill.JsonUtils;
import com.taotao.mapper.TbContentMapper;
import com.taotao.pojo.TbContent;
import com.taotao.pojo.TbContentExample;
import com.taotao.pojo.TbContentExample.Criteria;
import com.taotao.rest.dao.JedisClient;
import com.taotao.rest.service.ContentService;
//内容服务发布
@Service
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper contentMapper;
//把缓存添加到业务逻辑開始
@Autowired
private JedisClient jedisClient;
@Value("${INDEX_CONTENT_REDIS_KEY}")
private String INDEX_CONTENT_REDIS_KEY;
//把缓存添加到业务逻辑结束
@Override
public List<TbContent> getContentList(long contentCid) {
//把缓存添加到业务逻辑開始
//从缓存中取内容
try {
String result = jedisClient.hget(INDEX_CONTENT_REDIS_KEY, contentCid + "");
if (!StringUtils.isBlank(result)) {
//把字符串转换成list
List<TbContent> resultList = JsonUtils.jsonToList(result, TbContent.class);
return resultList;
}
} catch (Exception e) {
e.printStackTrace();
}
//把缓存添加到业务逻辑结束
// 根据内容分类id查询内容列表
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(contentCid);
// 执行查询
List<TbContent> list = contentMapper.selectByExample(example);
//把缓存添加到业务逻辑開始
//向缓存中添加内容
try {
//把list转换成字符串
String cacheString = JsonUtils.objectToJson(list);
jedisClient.hset(INDEX_CONTENT_REDIS_KEY, contentCid + "", cacheString);
} catch (Exception e) {
e.printStackTrace();
}
//把缓存添加到业务逻辑结束
return list;
}
}
resource.properties
【/taotao-rest】—【/src/main/resources】—【resource/】—【resource.properties】
#首页内容信息在redis中保存的key
INDEX_CONTENT_REDIS_KEY=INDEX_CONTENT_REDIS_KEY
启动:http://localhost:8082/
4 缓存同步
当后台管理系统,修改内容之后需要通知redis把修改的内容对应的分类id的key删除。
4.1. 添加缓存后的系统架构
4.2. 解决方案
在taotao-rest工程中发布一个服务。当后台管理系统修改内容后,调用此服务,同步缓存。
4.3. Dao层
使用JedisClient接口对应的实现类。
JedisClient.java
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/dao/】—【JedisClient.java】
package com.taotao.rest.dao;
/**
* 业务逻辑中添加缓存
* 添加jedis dao
* @author Lenovo
*
*/
public interface JedisClient {
String get(String key);
String set(String key, String value);
String hget(String hkey, String key);
long hset(String hkey, String key, String value);
long incr(String key);
long expire(String key, int second);
long ttl(String key);
long del(String key);
long hdel(String hkey, String key);
}
4.4. Service层
接收内容分类id,调用dao删除redis中对应的hash中key为分类id的项。
参数:内容分类id
返回值:TaotaoResult
RedisService.java
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/service/】—【RedisService.java】
package com.taotao.rest.service;
import com.taotao.common.utill.TaotaoResult;
/**
* 缓存同步
* @author Lenovo
*
*/
public interface RedisService {
TaotaoResult syncContent(long contentCid);
}
RedisServiceImpl.java
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/service/impl/】—【RedisServiceImpl.java】
package com.taotao.rest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.taotao.common.utill.ExceptionUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.rest.dao.JedisClient;
import com.taotao.rest.service.RedisService;
/**
* 缓存同步
* @author Lenovo
*
*/
@Service
public class RedisServiceImpl implements RedisService {
@Autowired
private JedisClient jedisClient;
@Value("${INDEX_CONTENT_REDIS_KEY}")
private String INDEX_CONTENT_REDIS_KEY;
@Override
public TaotaoResult syncContent(long contentCid) {
try {
jedisClient.hdel(INDEX_CONTENT_REDIS_KEY, contentCid + "");
} catch (Exception e) {
e.printStackTrace();
return TaotaoResult.build(500, ExceptionUtil.getStackTrace(e));
}
return TaotaoResult.ok();
}
}
4.5 Controller层
接收内容分类id,调用Service返回taotaoResult。
RedisController.java
【/taotao-rest】—【/src/main/java/】—【com/taotao/rest/controller/】—【RedisController.java】
package com.taotao.rest.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.rest.service.RedisService;
/**
* 缓存同步
* @author Lenovo
*
*/
@Controller
@RequestMapping("/cache/sync")
public class RedisController {
@Autowired
private RedisService redisService;
@RequestMapping("/content/{contentCid}")
@ResponseBody
public TaotaoResult contentCacheSync(@PathVariable Long contentCid) {
TaotaoResult result = redisService.syncContent(contentCid);
return result;
}
}
http://localhost:8081/rest/cache/sync/content/89
刷新一下前台页面就又产生了
4.6 同步缓存服务的调用
需要在后台管理系统中添加一个服务调用的逻辑。当修改内容信息后,需要调用此服务同步缓存。
ContentServiceImpl.java
【/taotao-manager-service】—【/src/main/java/】—【com/taotao/service/impl/】—【ContentServiceImpl.java】
package com.taotao.service.impl;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taotao.common.pojo.EUDataGridResult;
import com.taotao.common.utill.HttpClientUtil;
import com.taotao.common.utill.TaotaoResult;
import com.taotao.mapper.TbContentMapper;
import com.taotao.pojo.TbContent;
import com.taotao.pojo.TbContentExample;
import com.taotao.pojo.TbContentExample.Criteria;
import com.taotao.service.ContentService;
//内容管理
@Service
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper contentMapper;
// 同步缓存服务的调用开始
@Value("${REST_BASE_URL}")
private String REST_BASE_URL;
@Value("${REST_CONTENT_SYNC_URL}")
private String REST_CONTENT_SYNC_URL;
// 同步缓存服务的调用结束-
// 内容列表显示
@Override
public EUDataGridResult getContentList(long categoryId, int page, int rows) {
// 根据categoryId查询
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
criteria.andCategoryIdEqualTo(categoryId);
// 分页管理
PageHelper.startPage(page, rows);
List<TbContent> list = contentMapper.selectByExample(example);
EUDataGridResult result = new EUDataGridResult();
result.setRows(list);
PageInfo<TbContent> pageInfo = new PageInfo<>(list);
result.setTotal(pageInfo.getTotal());
return result;
}
// 內容添加
@Override
public TaotaoResult insertContent(TbContent content) {
// 补全pojo内容
content.setCreated(new Date());
content.setUpdated(new Date());
contentMapper.insert(content);
// 同步缓存服务的调用开始
//添加缓存同步逻辑
try {
HttpClientUtil.doGet(REST_BASE_URL + REST_CONTENT_SYNC_URL + content.getCategoryId());
} catch (Exception e) {
e.printStackTrace();
}
// 同步缓存服务的调用結束
return TaotaoResult.ok();
}
@Override
public TaotaoResult updataContent(TbContent content) {
// 填充属性
content.setUpdated(new Date());
// 更新内容
contentMapper.updateByPrimaryKeyWithBLOBs(content);
// 返回结果
return TaotaoResult.ok();
}
@Override
public TaotaoResult deleteContent(String ids) {
String[] idList=ids.split(",");
for (String id : idList) {
contentMapper.deleteByPrimaryKey(Long.valueOf(id));
}
return TaotaoResult.ok();
}
}
resource.properties
【/taotao-manager-web/】—【src/main/resources/】—【resource/】—【resource.properties】
#服务层基础
REST_BASE_URL=http://localhost:8081/rest
REST_CONTENT_SYNC_URL=/cache/sync/content/
后台添加一个大广告能显示则说明缓存添加成功