壹立方商城-Day06
首页轮播图动态展示
效果展示
动态从数据库中获取广告内容
前端分析
在e3-portal-web的index.jsp中,有一个首页读取广告信息的json格式的例子,所以前端只需要获得这样的json即可加载广告。
后端代码实现
Json数据格式:
[
{
"srcB": "http://image.taotao.com/images/2015/03/03/2015030304360302109345.jpg",
"height": 240,
"alt": "",
"width": 670,
"src": "http://image.taotao.com/images/2015/03/03/2015030304360302109345.jpg",
"widthB": 550,
"href": "http://sale.jd.com/act/e0FMkuDhJz35CNt.html?cpdad=1DLSUE",
"heightB": 240
}
]
分析:在e3-content-service获取 tbcontent的内容列表 即:list<TbContent>,在e3-portal-web封装这样的json,封装这样的json就需要一个pojo从list<TbContent>中获取信息,并转为前端需要的json格式。
服务层
从tb_content表中取数据,根据(叶子节点)内容分类id查询列表(内容列表)。
dao层
使用****
service层
在e3-content-interface创建接口,接收categoryId返回List<TbContent>
ContentService.java
/**
* 根据categoryId查询内容列表
* @param cid
* @return
*/
List<TbContent> getContentListByCid(long cid);
在e3-content-service实现接口
ContentServiceImpl.java
/**
* 根据内容分类categoryId查询内容列表---内容列表显示
* @param cid
* @return
*/
@Override
public List<TbContent> getContentListByCid(long cid) {
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
//设置查询条件
criteria.andCategoryIdEqualTo(cid);
//执行查询
List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);
return list;
}
表现层
在e3-portal-web工程中的pom.xml文件中添加manager-interface依赖
<dependency>
<groupId>cn.e3mall</groupId>
<artifactId>e3-content-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
在e3-portal-web工程中的springmvc.xml文件中引入服务
<dubbo:reference interface="cn.e3mall.content.service.ContentService" id="contentService" />
配置resource.properties配置文件
#轮播图内容的分类
CONTENT_LUNBO_ID=89
在springmvc.xml文件中加载配置文件
注意,配置多个配置文件,加载以后只生效一个
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:conf/resource.properties"/>
修改e3-portal-web工程下的index.jsp
删除静态的轮播图标签
添加遍历的jstl标签
小圆点地方做修改
e3-portal-web工程下的IndexController.java
package cn.e3mall.portal.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import cn.e3mall.content.service.ContentService;
import cn.e3mall.pojo.TbContent;
/**
* 首页展示Controller
* <p>Title: IndexController</p>
* @version 1.0
*/
@Controller
public class IndexController {
@Value("${CONTENT_LUNBO_ID}")
private Long CONTENT_LUNBO_ID;
@Autowired
private ContentService contentService;
@RequestMapping("/index")
public String showIndex(Model model) {
//查询内容列表
List<TbContent> ad1List = contentService.getContentListByCid(CONTENT_LUNBO_ID);
// 把结果传递给页面
model.addAttribute("ad1List", ad1List);
return "index";
}
}
启动工程
启动e3-manager、e3-content、e3-portal-web
查看页面结果
linux安装redis以及连接redis
redis的下载
官网地址:http://redis.io/
下载地址:http://download.redis.io/releases/redis-3.0.0.tar.gz
2.redis的安装
安装redis需要c语言的编译环境,如果没有gcc需要在线安装
yum -y install gcc-c++
测试是否有gcc环境
gcc: no input files 表示安装成功
[[email protected] ~]# gcc
gcc: no input files
安装步骤:
第一步:将redis的源码包上传到linux系统。选用e3-manager-dubbo-register-Redis服务器
用SecureCRT上传
清除之前安装的Redis
第二步:解压缩redis的源码包。
tar -xvf redis-3.0.0.tar.gz
第三步:进行编译。 cd到解压后的目录 输入命令:make
cd /redis-3.0.0
执行:make命令
make
第四步:进行安装。 输入命令:
make install PREFIX=/usr/local/redis
PREFIX 必须是大写的。
cd /usr/local/redis
有bin目录说明安装成功
3.连接redis
3.1redis服务端启动
第一种:前端启动模式
bin的目录
cd /usr/local/redis/
在bin目录下执行
./redis-server
这种方法启动后,这个终端就不能用了,只能新开一个终端了。
第二种:后台启动模式
第一步:将redis.conf配置文件复制到redis/bin下
redis.conf是配置文件
cp /su/redis-3.0.0/redis.conf /usr/local/redis/bin/
第二步:使用vim编辑redis.conf文件
将daemonize no修改为daemonize yes
第三步:启动redis
./redis-server redis.conf
第四步:检查redis进程
ps -ef|grep redis
或者
ps aux|grep redis
3.2客户端redis-cli连接redis
在redis/bin下,默认连接127.0.0.1:6379的本地redis服务
./redis-cli
健康检查
出现PONG表示正常
redi 也可以指定连接ip:端口
-h:连接的服务器的地址
-p:服务的端口号
./redis-cli -h 192.168.25.153 -p 6379
3.3关闭redis服务
第一种:通过客户端关闭
在redis/bin下
./redis-cli shutdown
第二种:使用kill命令
找到对应的redis的进程id 然后使用命令:(pid为进程id)
kill -9 pid
Redis的数据类型操作
Redis的持久化方案
Redis集群原理
redis-cluster架构图
redis-cluster投票:容错
架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的节点检测失效时才生效.通过投票机制
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot(哈希槽)上,cluster 负责维护node<->slot<->value
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
将key均匀的放在这些服务器上,让这些服务器都干活
Redis集群的搭建
环境搭建
制作6个redis实例
每个实例运行在不同的端口。需要修改redis.conf配置文件。配置文件中还需要把cluster-enabled yes前的注释去掉。
Redis集群中至少应该有三个节点。要保证集群的高可用,需要每个节点有一个备份机。
Redis集群至少需要6台服务器。搭建伪分布式。
搭建伪分布式。可以使用一台虚拟机运行6个redis实例。需要修改redis的端口号7001-7006
进入redis目录
[[email protected] redis]# cd /usr/local/redis/
在上一级目录下创建一个目录
[[email protected] redis]# mkdir ../redis-cluster
此时在local目录下就有一个redis-cluster目录
复制redis/bin 目录到redis-cluster/redis01目录下
[[email protected] local]# cp redis/bin/ redis-cluster/redis01 -r
进入redis01目录下
因为创建集群需要的是一个干净的redis目录,所以要删除这个目录下的appendonly.aof 和 dump.rdb文件,这两个文件时两种持久化方式创建的数据文件,一般情况下只有dump.rdb文件
执行命令删除文件:
[[email protected] redis01]# rm -f dump.rdb
[[email protected] redis01]# rm -f appendonly.aof
修改配置文件redis.conf
vim redis.conf
修改上面的端口号
将这里的注释打开
复制五个redis得到留个redis
修改每个redis的配置文件redis.conf的端口号7002 7003 7004 7005 7006
[[email protected] redis-cluster]# vim redis06/redis.conf
进去以后如果找不到端口号,就输入/port进行查找
启动每个redis实例
可以一个个的启动,也可以写一个批处理将所有的redis服务启动
vim start-all.sh
上面的批处理是执行在redis-cluster文件里的,下面的这个批处理更通用
cd /usr/local/redis-cluster/redis01/bin
./redis-server redis.conf
cd /usr/local/redis-cluster/redis02/bin
./redis-server redis.conf
cd /usr/local/redis-cluster/redis03/bin
./redis-server redis.conf
cd /usr/local/redis-cluster/redis04/bin
./redis-server redis.conf
cd /usr/local/redis-cluster/redis05/bin
./redis-server redis.conf
cd /usr/local/redis-cluster/redis06/bin
./redis-server redis.conf
授权执行文件权限
chmod u+x start-all.sh
启动redis服务
在redis-cluster目录下
./start-all.sh
查看服务是否启动
ps aux|grep redis
关闭集群
创建关闭集群的脚本
首先使用:vim 命令创建一个文件 redis-cluster-stop-all.sh
vim redis-cluster-stop-all.sh
内容如下
cd /usr/local/redis-cluster/redis01/bin
./redis-cli -p 7001 shutdown
cd /usr/local/redis-cluster/redis02/bin
./redis-cli -p 7002 shutdown
cd /usr/local/redis-cluster/redis03/bin
./redis-cli -p 7003 shutdown
cd /usr/local/redis-cluster/redis04/bin
./redis-cli -p 7004 shutdown
cd /usr/local/redis-cluster/redis05/bin
./redis-cli -p 7005 shutdown
cd /usr/local/redis-cluster/redis06/bin
./redis-cli -p 7006 shutdown
给权限
chmod u+x redis-cluster-stop-all.sh
进入[[email protected] src]# cd /su/redis-3.0.0/src目录下
找到.rb结尾的文件redis-trip.rb
将这个脚本文件复制到 /usr/local/redis-cluster/目录下
[[email protected] src]# cp redis-trib.rb /usr/local/redis-cluster/
或者
[[email protected] redis-cluster]# cp /su/redis-3.0.0/src/*.rb /usr/local/redis-cluster/redis-trib.rb
至此,redis实例制作完成!!!
rubby运行环境搭建
使用ruby脚本搭建集群。需要ruby的运行环境。
1、安装ruby
yum install ruby 环境安装
yum install rubygems 包管理器安装
2、安装ruby脚本运行使用的包。
上传redis-3.0.0.gem
进入redis-3.0.0.gem文件所在的目录su
cd /su/
执行指令
gem install redis-3.0.0.gem
此时redis-trib.rb脚本就可以运行了
使用ruby脚本搭建集群。
执行./redis-trib.sh
./redis-trib.rb create --replicas 1 192.168.25.129:7001 192.168.25.129:7002 192.168.25.129:7003 192.168.25.129:7004 192.168.25.129:7005 192.168.25.129:7006
分配方案确定
输入yes后开始搭建
集群搭建成功!!!
集群的使用方法
连接集群
Redis-cli连接集群,任意连接其中一台就可操作整个集群。
[[email protected] redis-cluster]# redis01/redis-cli -p 7004 -c
-c:代表连接的是redis集群
重定向到15495槽,192,168,25,129服务器的7003端口,然后把key放进去
使用java的jedis连接单机redis及redis集群
添加缓存
添加jedis依赖
添加到e3-content-service工程中的pom.xml文件中
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
连接单机redis
第一步:创建一个Jedis对象。需要指定服务端的ip及端口。
第二步:使用Jedis对象操作数据库,每个redis命令对应一个方法。
第三步:打印结果。
第四步:关闭Jedis
在e3-content-service工程中的test中新建一个测试
JedisTest.java
package cn.e3mall.jedis;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
public class JedisTest {
@Test
public void testJedis() throws Exception {
//创建一个连接Jedis对象,参数:host、port
Jedis jedis = new Jedis("192.168.25.129", 6379);
//直接使用jedis操作redis。所有jedis的命令都对应一个方法。
jedis.set("test123", "my first jedis test");
String string = jedis.get("test123");
System.out.println(string);
//关闭连接
jedis.close();
}
}
运行测试得到
使用连接池连接单机redis
第一步:创建一个JedisPool对象。需要指定服务端的ip及端口。
第二步:从JedisPool中获得Jedis对象。
第三步:使用Jedis操作redis服务器。
第四步:操作完毕后关闭jedis对象,连接池回收资源。
第五步:关闭JedisPool对象。
//使用连接池连接单击redis
@Test
public void testJedisPool() throws Exception {
//创建一个连接池对象,两个参数host、port
JedisPool jedisPool = new JedisPool("192.168.25.129", 6379);
//从连接池获得一个连接,就是一个jedis对象。
Jedis jedis = jedisPool.getResource();
//使用jedis操作redis
String string = jedis.get("test123");
System.out.println(string);
//关闭连接,每次使用完毕后关闭连接。连接池回收资源。
jedis.close();
//关闭连接池。
jedisPool.close();
}
连接集群redis
第一步:使用JedisCluster对象。需要一个Set<HostAndPort>参数。Redis节点的列表。
第二步:直接使用JedisCluster对象操作redis。在系统中单例存在。
第三步:打印结果
第四步:系统关闭前,关闭JedisCluster对象。单例的
@Test
public void testJedisCluster() throws Exception {
//创建一个JedisCluster对象。有一个参数nodes是一个set类型。set中包含若干个HostAndPort对象。
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.25.129", 7001));
nodes.add(new HostAndPort("192.168.25.129", 7002));
nodes.add(new HostAndPort("192.168.25.129", 7003));
nodes.add(new HostAndPort("192.168.25.129", 7004));
nodes.add(new HostAndPort("192.168.25.129", 7005));
nodes.add(new HostAndPort("192.168.25.129", 7006));
JedisCluster jedisCluster = new JedisCluster(nodes);
//直接使用JedisCluster对象操作redis。
jedisCluster.set("test", "123");
String string = jedisCluster.get("test");
System.out.println(string);
//关闭JedisCluster对象
jedisCluster.close();
}
使用spring管理通用连接redis的接口
将jedis的接口和实现类放到e3-common工程中的cn.e3mall.common.jedis包内
文件错误的原因是因为缺少JedisCluster和JedisPool的依赖
在e3-common工程中的pom.xml中添加JedisCluster和JedisPool的依赖
将e3-content-service工程中的pom.xml中的redis依赖剪切到e3-common工程中的pom.xml中
<!-- Redis客户端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
此时所有工程中都会有这个依赖
接口定义
JedisClient.java
package cn.e3mall.common.jedis;
import java.util.List;
public interface JedisClient {
// Redis SET命令用于在Redis键中设置一些字符串值
String set(String key, String value);
// 根据key去查询相应的值
String get(String key);
// 判断key在Redis缓存中是否存在
Boolean exists(String key);
// 设置key的过期时间
Long expire(String key, int seconds);
// Redis TTL 命令以秒为单位返回 key 的剩余过期时间
Long ttl(String key);
// Redis Incr 命令将 key 中储存的数字值增一
Long incr(String key);
/**
* Redis Hset 命令用于为哈希表中的字段赋值 。 如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。
* 如果字段已经存在于哈希表中,旧值将被覆盖。
*
* @param key
* @param field
* @param value
* @return
*/
Long hset(String key, String field, String value);
// Redis Hget 命令用于返回哈希表中指定字段的值
String hget(String key, String field);
// Redis Hdel 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。
Long hdel(String key, String... field);
// 查询所有的hash类型的列表
Boolean hexists(String key, String field);
List<String> hvals(String key);
Long del(String key);
}
连接单机redis实现类
封装常用的redis命令
JedisClientPool.java
package cn.e3mall.common.jedis;
import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisClientPool implements JedisClient {
private JedisPool jedisPool;
public JedisPool getJedisPool() {
return jedisPool;
}
public void setJedisPool(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
@Override
public String set(String key, String value) {
Jedis jedis = jedisPool.getResource();
String result = jedis.set(key, value);
jedis.close();
return result;
}
@Override
public String get(String key) {
Jedis jedis = jedisPool.getResource();
String result = jedis.get(key);
jedis.close();
return result;
}
@Override
public Boolean exists(String key) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.exists(key);
jedis.close();
return result;
}
@Override
public Long expire(String key, int seconds) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.expire(key, seconds);
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 incr(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}
@Override
public Long hset(String key, String field, String value) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hset(key, field, value);
jedis.close();
return result;
}
@Override
public String hget(String key, String field) {
Jedis jedis = jedisPool.getResource();
String result = jedis.hget(key, field);
jedis.close();
return result;
}
@Override
public Long hdel(String key, String... field) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.hdel(key, field);
jedis.close();
return result;
}
@Override
public Boolean hexists(String key, String field) {
Jedis jedis = jedisPool.getResource();
Boolean result = jedis.hexists(key, field);
jedis.close();
return result;
}
@Override
public List<String> hvals(String key) {
Jedis jedis = jedisPool.getResource();
List<String> result = jedis.hvals(key);
jedis.close();
return result;
}
@Override
public Long del(String key) {
Jedis jedis = jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
}
}
连接集群redis实现类
JedisClientCluster.java
package cn.e3mall.common.jedis;
import java.util.List;
import redis.clients.jedis.JedisCluster;
public class JedisClientCluster implements JedisClient {
private JedisCluster jedisCluster;
public JedisCluster getJedisCluster() {
return jedisCluster;
}
public void setJedisCluster(JedisCluster jedisCluster) {
this.jedisCluster = jedisCluster;
}
@Override
public String set(String key, String value) {
return jedisCluster.set(key, value);
}
@Override
public String get(String key) {
return jedisCluster.get(key);
}
@Override
public Boolean exists(String key) {
return jedisCluster.exists(key);
}
@Override
public Long expire(String key, int seconds) {
return jedisCluster.expire(key, seconds);
}
@Override
public Long ttl(String key) {
return jedisCluster.ttl(key);
}
@Override
public Long incr(String key) {
return jedisCluster.incr(key);
}
@Override
public Long hset(String key, String field, String value) {
return jedisCluster.hset(key, field, value);
}
@Override
public String hget(String key, String field) {
return jedisCluster.hget(key, field);
}
@Override
public Long hdel(String key, String... field) {
return jedisCluster.hdel(key, field);
}
@Override
public Boolean hexists(String key, String field) {
return jedisCluster.hexists(key, field);
}
@Override
public List<String> hvals(String key) {
return jedisCluster.hvals(key);
}
@Override
public Long del(String key) {
return jedisCluster.del(key);
}
}
spring配置
将单机版集群版配置,配置到spring容器中
在e3-content-service中创建spring/applicationContext-redis.xml
在单机版的配置中,我们使用构造方法创建JedisPool对象,参数为host和port。JedisPool对象要注入到JedisClientPool的依赖中,然后创建JedisClientPool对象
在集群版的配置中,使用构造方法创建jedisCluster对象,参数为set<HostAndPort>。使用构造方法创建HostAndPort对象时,需要参数host和post。最后创建JedisClientCluster对象,并将jedisCluster注入依赖。
applicationContext-redis.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.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<!-- 连接redis单机版 -->
<bean id="jedisClientPool" class="cn.e3mall.common.jedis.JedisClientPool">
<property name="jedisPool" ref="jedisPool"></property>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.25.129"/>
<constructor-arg name="port" value="6379"/>
</bean>
<!-- 连接redis集群 -->
<!-- <bean id="jedisClientCluster" class="cn.e3mall.common.jedis.JedisClientCluster">
<property name="jedisCluster" ref="jedisCluster"/>
</bean>
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg name="nodes">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.129"></constructor-arg>
<constructor-arg name="port" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.129"></constructor-arg>
<constructor-arg name="port" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.129"></constructor-arg>
<constructor-arg name="port" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.129"></constructor-arg>
<constructor-arg name="port" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.129"></constructor-arg>
<constructor-arg name="port" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.25.129"></constructor-arg>
<constructor-arg name="port" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
</bean> -->
</beans>
测试访问
单机redis配置测试
我们注释掉集群redis配置,并在applicationContext-redis.xml里面加上<context:annotation-config/>,编写测试类。
可以成功访问redis
在e3-content-service工程的test里写一个测试代码
JedisClientTest.java
package cn.e3mall.jedis;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.e3mall.common.jedis.JedisClient;
public class JedisClientTest {
@Test
public void testJedisClient() throws Exception {
// 初始化spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:spring/applicationContext-redis.xml");
// 从容器中获得JedisClient对象
JedisClient jedisClient = applicationContext.getBean(JedisClient.class);
jedisClient.set("mytest", "jedisClient");
String string = jedisClient.get("mytest");
System.out.println(string);
}
}
集群redis配置测试
集群测试的时候不需要改java代码,只需要把applicationContext-redis.xml中集群的配置文件打开,把单机的配置文件注释即可
所以单机版和集群版的切换只需要更改一下配置文件就可以了
注意:单机版和集群版不能共存,使用单机版时注释集群版的配置。使用集群版,把单机版注释。
向业务逻辑中添加缓存
为什么要添加缓存?我们在加载首页大广告时,由于大广告在数据库中的内容,并不是每时每刻都在变化,所以我们每次都从数据库中获取会很消耗资源,所以我们使用redis做缓存。
用户访问首页时:每次先从缓存中获取,如果缓存中没有广告的内容,就从数据库中获取,并将获取的广告内容放入缓存中,以便下次从缓存中获取,减少访问数据库的次数。
管理人员在商城后台做内容修改、增加、删除时:由于管理人员是修改数据库中的内容,并不能修改缓存中的内容,用户很有可能每次访问看到的都是没有更改前的广告内容,所以管理人员是修改数据库中的内容时,删除缓存中的内容即可。然后又回到用户访问首页时
HASH_KEY:HASH
|--KEY:VALUE
|--KEY:VALUE
|--KEY:VALUE
|--KEY:VALUE
缓存加的位置
加缓存主要是为了减小数据库的压力,如果缓存加在表现层,那么就跟服务层和数据库都没有关系了,如果加在服务层,那么就与数据库无关
所以缓存的添加位置在服务层和表现层加都可以,但是如果加在表现层,那么只能是这个表现层用的到,其他的表现层就用不到了
service层添加缓存
在e3-content-service的ContentServiceImpl中添加缓存
首先我们防止redis中的String类型(或者list、set)的key:cid=89太过简单,使用hash类型(ps:hash类型,通过key找到feild,通过feild找到value)
我们自定义一个key叫做TBCONTENT_KEY,feild使用cid,value就是转换为json后的List<TbContent>。(你也可以直接使用String、list、set类型,key使用categoryId,value=转换为json后的List<TbContent>)
将key放入配置文件中
新建一个resource/resource.properties,专门存放key。
内容如下
#内容列表在redis中缓存的key
CONTENT_LIST=CONTENT_LIST
加载properties文件
在e3-content-service工程中的applicationContext-dao.xml文件中配置
配置文件的加载,如果加载多个,只认一个,我们的配置文件加载在dao层加载,所以将文件名用*代替,表示加载所有properties文件
<!-- 加载属性文件 -->
<context:property-placeholder location="classpath:conf/*.properties" />
注入key和jedisClient对象
@Autowired
private JedisClient jedisClient;
//从缓存中获取大广告的key
@Value("${CONTENT_KEY}")
private String CONTENT_KEY;
编写添加缓存代码
每次先从缓存中获取,如果缓存中没有广告的内容,就从数据库中获取,并将获取的广告内容放入缓存中,以便下次从缓存中获取
中间可以加上System.out.println("xxxx");方便查看效果
e3-content-service工程中的ContentServiceImpl.java
/**
* 根据内容分类categoryId查询内容列表---内容列表显示
*
* @param cid
* @return
*/
@Override
public List<TbContent> getContentListByCid(long cid) {
// 查询缓存
try {
// 如果缓存中有直接响应结果
String json = jedisClient.hget(CONTENT_LIST, cid + "");
if (StringUtils.isNotBlank(json)) {
List<TbContent> list = JsonUtils.jsonToList(json, TbContent.class);
return list;
}
} catch (Exception e) {
e.printStackTrace();
}
// 如果没有查询数据库
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
// 设置查询条件
criteria.andCategoryIdEqualTo(cid);
// 执行查询
List<TbContent> list = contentMapper.selectByExampleWithBLOBs(example);
// 把结果添加到缓存
try {
// 这里类似于 hset hash1 field1 2 对应下面的
// hset CONTENT_LIST cid JsonUtils.objectToJson(list)
// 这个方法JsonUtils.objectToJson(list)就是将list转换成字符串,因为hashset中存的是字符串
jedisClient.hset(CONTENT_LIST, cid + "", JsonUtils.objectToJson(list));
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
启动
启动zookpeer
进入zookpeer目录
[[email protected] bin]# cd /su/zookeeper-3.4.6/bin/
启动zookpeer
[[email protected] bin]# ./zkServer.sh start
maven install e3-common 启动e3-content e3-manager e3-portal-web
第一次访问网站的时候,所有的数据都来自数据库
第二次访问的时候,就会从redis缓存中取出数据,这样就可以减少每一次访问都查询数据库,对数据库的压力
缓存同步
逻辑解析
首先在后台内容管理里面添加内容--例如大广告本来有四个,再添加一个
添加过后,按照理论来说,前台页面的大广告位值会有五张图片
可以看到,前台大广告位还是只有四张图片
这是因为前台的数据在第二次访问的时候都是从redis缓存中取出的,后台改了数据,但是前台取数据的时候不是从后台取出的,所以大广告位依然只有四张图
这时就要用到缓存同步技术让后台中的数据同步到redis缓存中
缓存同步实现
实现原理,在后台做增删改操作的时候都要在增删改操作中实现缓存同步---删除缓存中同步的相应的数据
相应的数据:缓存中会存在很多缓存,例如大广告,小广告等,我们要做的是删除我们修改数据的缓存(就是hash1中的field1,2,3.。。),其他缓存保持不变
实现缓存同步的位值
/**
* 内容管理----添加
*/
@Override
public E3Result addContent(TbContent content) {
//将内容数据插入到内容表
content.setCreated(new Date());
content.setUpdated(new Date());
//插入到数据库
contentMapper.insert(content);
//缓存同步,删除缓存中对应的数据。
jedisClient.hdel(CONTENT_LIST, content.getCategoryId().toString());
return E3Result.ok();
}
参考文章
原文https://blog.****.net/pdsu161530247/article/details/81901507#t0
原文https://blog.****.net/pdsu161530247/article/details/81902341
原文:https://blog.****.net/pdsu161530247/article/details/81903944