常用的redis命令,多敲几遍就会了。
redis是用来做什么的,缓存啊 CacheClient。
缓存的使用位置,service层。
从JedisPool中获取一个jedis对象,去操作redis。
//set集合中包含多个
H
o
s
t
A
n
d
P
o
r
t
\color{red}{HostAndPort}
HostAndPort对象
Set nodes = new HashSet<>();
//在set集合中添加redis节点的地址和端口号
nodes.add(new HostAndPort(“192.168.1.201”, 6379));
nodes.add(new HostAndPort(“192.168.1.201”, 6378));
//需要一个set集合,redis节点的host和port
JedisCluster jedisCluster = new JedisCluster(nodes);
所有的后台业务逻辑其实就四种:增删改查操作,不就是几个增删改查么,对不对?很简单的。
一百万人同时访问首页,查询一百万次数据库?不现实,使用redis缓存处理;高频使用数据。首页一般是需要缓存的,不经常变化,高频访问。
为什么要在服务层添加缓存?
在服务层添加缓存,如果在表现层添加缓存,使用微服务架构,可能其他的表现层也需要添加缓存,所以统一添加在
服
务
层
\color{red}{服务层}
服务层。
常用类:
J
e
d
i
s
P
o
o
l
、
J
e
d
i
s
、
J
e
d
i
s
C
l
u
s
t
e
r
、
H
o
s
t
A
n
d
P
o
r
t
\color{red}{JedisPool、Jedis、JedisCluster、HostAndPort}
JedisPool、Jedis、JedisCluster、HostAndPort
根
据
要
操
作
的
数
据
类
型
的
不
同
,
选
择
不
用
的
方
法
s
e
t
,
h
s
e
t
,
l
p
u
s
h
等
等
\color{red}{根据要操作的数据类型的不同,选择不用的方法set,hset,lpush等等}
根据要操作的数据类型的不同,选择不用的方法set,hset,lpush等等
查询缓存,执行查询,添加缓存。
StringUtils类的使用,判断当前字符串是否为非空,经常用到的。
需要把jedis依赖的jar包添加到工程中,Maven工程中需要把jedis的坐标添加到依赖。
内容分类id需要是固定的。可以配置到属性文件中,相当于常量。
首页轮播图展示 (四个功能,看看使用的是哪一个操作:增删改查)
如
何
实
现
缓
存
过
期
?
\color{red}{如何实现缓存过期?}
如何实现缓存过期?
缓存使用流程:查询内容列表时添加缓存的步骤:
1、查询数据库之前先查询缓存。
2、查询到结果,直接响应结果。缓存中存储的是字符串,需要经常用到序列化和反序列化。
3、查询不到,缓存中没有需要查询数据库。
4、把查询结果添加到缓存中。
5、返回结果。
添加缓存不能影响正常的业务逻辑。向业务逻辑中添加缓存
查询缓存,向缓存中添加数据。初始化Spring容器。从容器中获得JedisClient对象。
Redis集群Spring文件的配置。
如何实现缓存同步?
如果缓存存在,数据库中的数据改变了,如何同步?增删改都需要进行缓存同步,直接把缓存删除即可。
缓存同步:删除缓存中对应的数据。最好不要删除整条键值对,修改什么删除什么即可,要不然整条数据都要进行查询,增加数据库压力。
如果查询使用了缓存操作,那么对应的增删改也要实现缓存同步。
如何实现缓存同步?
如果缓存存在,数据库中的数据改变了,如何同步?增删改都需要进行缓存同步,直接把缓存删除即可。
缓存同步:删除缓存中对应的数据。最好不要删除整条键值对,修改什么删除什么即可,要不然整条数据都要进行查询,增加数据库压力。
如果查询使用了缓存操作,那么对应的增删改也要实现缓存同步。
package cn.e3mall.serverimpl;
import cn.e3mall.common.E3Result;
import cn.e3mall.common.JedisClient;
import cn.e3mall.common.JsonUtils;
import cn.e3mall.mapper.TbContentMapper;
import cn.e3mall.pojo.TbContent;
import cn.e3mall.service.ContentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
/**
* describe:内容管理
*
* @author chenrushui
* @date 2018/07/16
*/
@Service
public class ContentServiceImpl implements ContentService {
@Autowired
private TbContentMapper tbContentMapper;
/**
* 创建JedisClient对象,进行缓存操作处理
*/
@Autowired
private JedisClient jedisClient;
/**
* 添加新的内容
*
* @param tbContent
* @return
*/
@Override
public E3Result addContent(TbContent tbContent) {
//前端有些数据没有传递
tbContent.setCreated(new Date());
tbContent.setUpdated(new Date());
tbContentMapper.insert(tbContent);
try {
jedisClient.hdel("CONTENT_LIST", tbContent.getCategoryId() + "");
} catch (Exception e) {
e.printStackTrace();
}
return E3Result.ok();
}
/**
* 通过分类id获取category_id列表
*
* @param category_id
* @return
*/
@Override
public List<TbContent> getContentByCid(long category_id) {
//查询缓存报错
try {
//查询缓存
String json = jedisClient.hget("CONTENT_LIST", category_id + "");
//如果缓存中有,直接返回;StringUtils类的使用
if (!StringUtils.isEmpty(json)) {
List<TbContent> tbContents = JsonUtils.jsonToList(json, TbContent.class);
return tbContents;
}
} catch (Exception e) {
e.printStackTrace();
}
//如果没有,查询数据库
List<TbContent> tbContents = tbContentMapper.selectContentByCategoryId(category_id);
//添加缓存报错
try {
//把结果添加到缓存
jedisClient.hset("CONTENT_LIST", category_id + "", JsonUtils.objectToJson(tbContents));
} catch (Exception e) {
e.printStackTrace();
}
//返回结果
return tbContents;
}
}
Jedis的使用
package cn.e3mall.test;
import org.junit.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 java.util.Set;
/**
* describe:jedis的使用
*
* @author chenrushui
* @date 2018/07/17
*/
public class JedisTest {
/**
* 每次都要创建一个连接对象,用完关闭,浪费资源和性能
* Jedis,JedisPool,JedisCluster,HostAndPort,set集合(无序不能重复)
*/
@Test
public void testJedis() {
//创建一个jedis对象,参数为host,port
Jedis jedis = new Jedis("192.168.1.201", 6379);
//权限认证
jedis.auth("redis123");
//直接使用jedis操作redis,所有的命令都对应一个方法。
jedis.set("test", "123");
String result = jedis.get("test");
System.out.println(result);
//关闭连接
jedis.close();
}
/**
* 使用JedisPool操作redis,项目中常用
* 需要对连接池参数进行配置
*/
@Test
public void testJedisPool() {
//创建一个连接池对象,host和port
JedisPool jedisPool = new JedisPool("192.168.1.201", 6379);
//从连接池中获取一个连接,就是jedis对象 getResource()获取一个连接资源。
Jedis jedis = jedisPool.getResource();
jedis.auth("redis123");
jedis.set("TEST", "2222");
System.out.println(jedis.get("TEST"));
//关闭连接,连接池回收资源。
jedis.close();
//关闭连接池,一般项目中不会关闭
jedisPool.close();
}
/**
* 连接redis集群
*/
@Test
public void testJedisCluster() {
//set集合中包含多个HostAndPort对象
Set<HostAndPort> nodes = new HashSet<>();
//在set集合中添加redis节点的地址和端口号
nodes.add(new HostAndPort("192.168.1.201", 6379));
nodes.add(new HostAndPort("192.168.1.201", 6378));
//需要一个set集合,redis节点的host和port
JedisCluster jedisCluster = new JedisCluster(nodes);
//直接使用jedisCluster对象操作redis集群
jedisCluster.set("test4", "4444");
System.out.println(jedisCluster.get("test4"));
jedisCluster.close();
}
}
测试testJedisClient
@Test
public void testJedisClient() {
//初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-redis.xml");
//从容器中获取JedisClient对象
JedisClient jedisClient = context.getBean(JedisClient.class);
jedisClient.set("testClient", "11111");
System.out.println(jedisClient.get("testClient"));
//通过@Autowired创建对象,
//通过在配置文件中添加bean创建对象,如果提供了set和get方法,就使用property创建对象,
//如果通过构造函数创建对象。
}
spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--连接redis单机版-->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<!--通过构造方法创建对象-->
<constructor-arg name="host" value="192.168.1.201"/>
<constructor-arg name="port" value="6379"/>
</bean>
<!--连接redis单机版-->
<bean id="jedisClientPool" class="cn.e3mall.common.JedisClientPool">
<!--通过property为属性赋值-->
<property name="jedisPool" ref="jedisPool"/>
</bean>
<!--连接redis集群-->
<bean id="jedisClientCluster" class="cn.e3mall.common.JedisClientCluster">
<property name="jedisCluster" ref="jedisCluster"></property>
</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.1.201"/>
<constructor-arg name="port" value="6379"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.1.201"/>
<constructor-arg name="port" value="6378"/>
</bean>
</set>
</constructor-arg>
</bean>
</beans>
web.xml 文件:新添加配置文件的引入spring-redis.xml
<!--加载spring的配置文件:配置文件的位置;全局的参数,都可以使用-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!--加载配置文件:spring.xml,classpath:spring-redis.xml,spring.xml文件先加载,spring-mvc.xml文件后面进行加载-->
<param-value>classpath:spring.xml,classpath:spring-redis.xml</param-value>
</context-param>
JedisClient接口 统一接口封装
package cn.e3mall.common;
/**
* describe:JedisClient接口
*
* @author chenrushui
* @date 2018/07/17
*/
public interface JedisClient {
/**
* 存储数据
*
* @param key
* @param value
* @return
*/
String set(String key, String value);
/**
* 获取数据
*
* @param key
* @return
*/
String get(String key);
/**
* 当前缓存中是否存在
*
* @param key
* @return
*/
Boolean exists(String key);
/**
* 设置缓存的过期时间
*
* @param key
* @param seconds
* @return
*/
Long expire(String key, int seconds);
/**
* 检查某一缓存的状态
*
* @param key
* @return
*/
Long ttl(String key);
/**
* 主键自增
*
* @param key
* @return
*/
Long incr(String key);
/**
* 存储HashMap类型的值
*
* @param key
* @param field
* @param value
* @return
*/
Long hset(String key, String field, String value);
/**
* 获取HashMap的值
*
* @param key
* @param field
* @return
*/
String hget(String key, String field);
/**
* 刪除键值对
* @param key
* @param field
* @return
*/
Long hdel(String key, String... field);
}