第七天-cms系统添加缓存、redis、缓存同步

目录

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/

后台添加一个大广告能显示则说明缓存添加成功

猜你喜欢

转载自blog.csdn.net/weixin_46267445/article/details/118264924
今日推荐