NOSQL
什么是NOSQLNOSQL
NoSQL(NoSQL=Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库。
解决什么问题
- web程序不再仅仅专注在功能上,同时也在追求性能;
- 对数据库高并发读写的需求(High performance),现在数据库并发负载非常高,往往要达到每秒上万次读写请求,关系数据库应付上万次SQL查询还勉强顶得住,但是应付上万次SQL写数据请求,硬盘IO就已经无法承受了;
- 对海量数据的高效率存储和访问的需求(Huge Storage),对于关系数据库来说,在一张2.5亿条记录的表里面进行SQL查询,效率是极其低下乃至不可忍受的;
- 对数据库的高可扩展性和高可用性的需求(High Scalability && High Availability-),对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移;
主流的NOSQL产品
- 主流产品:redis,mongoDB,CouchDB,riak等
- 键值(Key-Value)存储数据库—redis:主要使用内存,有两种持久化方案(RDB和AOF),速度非常快,一般做分布式缓存使用;
- 文档型数据库-MongoDB:主要使用硬盘存储,所以不会担心数据丢失,速度介于redis和传统数据库之间,但是mongodb更擅长存储大文本数据,以及一些非结构化数据,mongodb比redis的数据类型更加丰富,例如:存储小说网站的小说,存储电商网站的评论等这些数据。
Redis
redis概述
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库。
redis的应用场景
- 缓存(数据查询、短连接、新闻内容、商品内容等等);
- 聊天室的在线好友列表;
- 任务队列。(秒杀、抢购、12306等等);
- 应用排行榜;
- 网站访问统计;
- 数据过期处理(可以精确到毫秒);
- 分布式集群架构中的session分离
业务流程
- 获取数据的时候先从redis中获取,如果获取到数据则直接返回,就不用访问数据库了;
- 如果获取不到数据,可以从数据库中查询,查询到后放入redis中一份,下回就可以直接从redis中查询到;
这样大大降低了数据库的高并发访问压力。
持久化方案
- RDB(默认) 分时持久化:可以在配置文件中设定,多长时间持久化一次,持久化次数少也就是操作硬盘的次数少,速度快.但是如果在没有完成持久化前,如果服务器断电,则内存中没有持久化的数据会丢失;
- AOF 实时持久化:每次向redis中做增删改操作, 都会将数据持久化到硬盘上,数据可靠性高,不会丢失,但是速度慢。
redis安装
windows:
- window版的安装及其简单,
- 解压Redis压缩包完成即安装完毕,
- 双击Redis目录中redis-server.exe可以启动redis服务,Redis服务占用的端口是6379,
- 关闭Redis的控制台窗口就可以关闭Redis服务
linux:
- 将redis在Linux的安装包上传到/usr/local当中,
- 解压:tar -xvf redis-4.0.9.tar.gz
- 编译安装:
- 进入到redis目录(cd /usr/local/redis-4.0.9/),
- make
- make install PREFIX='/usr/local/redis-4.0.9/6379'
- 启动:/usr/local/redis-4.0.9/6379/bin/redis-server
- 修改配置文件:
- 把/usr/local/redis-4.0.9/目录下的配置文件复制一份到6379目录下(cp redis.conf /usr/local/redis-4.0.9/6379/bin/)
- 修改配置文件:
- #bind 127.0.0.1 # 将这行代码注释,监听所有的ip地址,外网可以访问
- protected-mode no # 把yes改成no,允许外网访问
- daemonize yes # 把no改成yes,后台运行
- 重新启动:./redis-server redis.conf
- 查看进程:ps -ef|grep redis
Redis的数据类型
- redis是一种高级的key-value的存储系统,其中value支持五种数据类型。
- Redis的5种数据类型:
- 字符串(String)
- 哈希(hash)
- 字符串列表(list)
- 字符串集合(set)
- 序字符串集合(sorted set)
- key的定义注意点:
- key不要太长,最好不要操作1024个字节,这不仅会消耗内存还会降低查找效率;
- key不要太短,如果太短会降低key的可读性
- 在项目中,key最好有一个统一的命名规范
基本操作
- 字符串类型string
- 概述:设定key持有指定的字符串value,如果该key存在则进行覆盖操作。总是返回”OK”
- 操作:
- set key value:set name it
- get key:get it,获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息;
- del key:del it
- 示例:
- 哈希类型hash
- 概述:Redis中的Hash类型可以看成具有String Key和String Value的map容器,所以该类型非常适合于存储值对象的信息;
- 操作:
- hset key field value:为指定的key设定field/value对(键值对),
hset myhash name it——存入hash类型值myhash存的值为name:it - hget key field:返回指定的key中的field的值
- hdel key field [field … ]:可以删除一个或多个字段,返回值是被删除的字段个数
- hgetall key:可以获取该键的所有数据
- 示例:
- hset key field value:为指定的key设定field/value对(键值对),
- 列表类型list
- 概述:在Redis中,List类型是按照插入顺序排序的字符串链表,和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素,在插入时,如果该键并不存在,Redis将为该键创建一个新的链表,与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除,List中可以包含的最大元素数量是4294967295。
- 操作:
- lpush key values[value1 value2…]:lpush mylist a b c——在指定的key所关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据,插入成功,返回元素的个数。
- lpop key:lpop mylist返回并弹出指定的key关联的链表中的第一个元素,即头部元素,如果该key不存在,返回nil;若key存在,则返回链表的头部元素。
- rpop key:从尾部弹出元素,与lpop key相反。
- lrange key:遍历该键的所有数据
- lrange key 0 2:返回0 1 2
- lrange key 0 -1:返回所有
- 示例:
- 集合类型set
- 概述:在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作,Set集合中不允许出现重复的元素。
- 操作:
- sadd key values[value1、value2…]:sadd myset a b c:向set中添加数据,如果该key的值已有则不会重复添加
- smembers key:smembers myset:获取set中所有的成员
- srem key members[member1、member2…]:srem myset a b:删除set中指定的成员
- 有序集合类型sortset
- 概述:在redis中,可以保证不重复的元素,仍然可以进行排序。
- 操作:
- zadd key values[value1、value2…]:zadd mysort 5 zs 10 lisi 7 wc 8 xk
- zrange key 索引 索引:zrange mysort 0 -1
- zrem key value:zrem mysort lisi
Redis的通用命令
- keys pattern:获取所有与pattern匹配的key,返回所有与该key匹配的keys,*表示任意一个或多个字符,?表示任意一个字符。
- del key1 key2…:删除指定的key
- exists key:判断该key是否存在,1代表存在,0代表不存在
- type key:获取指定key的类型。该命令将以字符串的格式返回,返回的字符串为string、list、set、hash,如果key不存在返回none
Redis的持久化
- 概述:Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化,Redis支持两种方式的持久化,可以单独使用其中一种或将二者结合使用。
- 一种是RDB方式,一种是AOF方式:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
- RDB持久化(默认支持,无需配置):该机制将以日志的形式记录服务器所处理的每一个写操作。
- AOF持久化:在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
- 无持久化:我们可以通过配置的方式禁用Redis服务器的持久化功能,这样我们就可以将Redis视为一个功能加强版的memcached了
- 一种是RDB方式,一种是AOF方式:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。
- redis可以同时使用RDB和AOF。
- RDB持久化机制:
- RDB持久化机制优点:一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的
- RDB持久化机制缺点:如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
- 快照触发条件:
- 客户端执行命令save和bgsave会生成快照;
- 根据配置文件save m n规则进行自动快照;
- 主从复制时,从库全量复制同步主库数据,此时主库会执行bgsave命令进行快照;
- 客户端执行数据库清空命令FLUSHALL时候,触发快照;
- 客户端执行shutdown关闭redis时,触发快照;
- RDB持久化机制的配置:
-
- save m n:
- 配置快照(rdb)促发规则,格式:save <seconds> <changes>
- save 900 1 900秒内至少有1个key被改变则做一次快照
- save 300 10 300秒内至少有10个key被改变则做一次快照
- save 60 10000 60秒内至少有10000个key被改变则做一次快照
- #关闭该规则使用save “ ”
- dbfilename dump.rdb:rdb持久化存储数据库文件名,默认为dump.rdb
- stop-write-on-bgsave-error yes:yes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no表明忽略错误继续写文件。
- rdbchecksum yes:在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。
- dir "./":数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限
- rdbcompression yes: 是否开启RDB文件压缩,该功能可以节约磁盘空间
- save m n:
-
- AOF持久化机制:
- AOF概述:当redis存储非临时数据时,为了降低redis故障而引起的数据丢失,redis提供了AOF(Append Only File)持久化,从单词意思讲,将命令追加到文件。AOF可以将Redis执行的每一条写命令追加到磁盘文件(appendonly.aof)中, 在redis启动时候优先选择从AOF文件恢复数据。由于每一次的写操作,redis都会记录到文件中,所以开启AOF持久化会对性能有一定的影响, AOF持久化数据丢失更少,其消耗内存更少(RDB方式执行bgsve会有内存拷贝)
- 开启AOF持久化: 默认情况下,redis是关闭了AOF持久化,开启AOF通过配置appendonly为yes开启, 将appendonly修改为yes,开启aof持久化机制,默认会在目录下产生一个appendonly.aof文件, 我们修改配置文件或者在命令行直接使用config set修改,在用config rewrite同步到配置文件。通过客户端修改好处是不用重启redis,AOF持久化直接生效
- config get appendonly: 查询配置状态
- config set appendonly yes: 修改配置
- config rewrite: 写入到redis.conf中
- 配置: appendfsync
- always: 每执行一次更新命令,持久化一次
- everysec: 每秒钟持久化一次
- no: 不持久化
- RDB-AOF混合持久化:
通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改。
jedis的介绍
使用Jedis操作redis需要导入jar包如下:(Jedis相当于redis的连接池)
- jedis常用API
- new Jedis(host, port):创建jedis对象,参数host是redis服务器地址,参数port是redis服务端口
- set(key,value):设置字符串类型的数据
- get(key):获得字符串类型的数据
- hset(key,field,value):设置哈希类型的数据
- hget(key,field):获得哈希类型的数据
- lpush(key,values):设置列表类型的数据
- lpop(key):列表左面弹栈
- rpop(key):列表右面弹栈
- del(key):删除指定的key
- jedis的基本操作:
- jedis连接池的基本概念:
- jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术
- 示例代码:
Spring-data-redis
- Spring-data-redis概述:
- Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis, JRedis, and RJC)进行了高度封装,RedisTemplate提供了redis各种操作、异常处理及序列化,支持发布订阅
- Spring-data-redis功能:
- 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对jedis客户端中大量api进行了归类封装
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
- ValueOperations:简单K-V操作
- Spring-data-redis入门程序:
- 1.构建Maven工程 SpringDataRedisDemo jar工程
- 2.引入Spring/Jedis和SpringDataRedis依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<!-- 缓存 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.2.RELEASE</version>
</dependency>
</dependencies>
- 3.在src/main/resources建立redis-config.properties
redis.host=192.168.1.9
redis.port=6379
redis.pass=
redis.database=0
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=true
- 4.在src/main/resources创建applicationContext-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath*:*.properties" />
<!-- redis 相关配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="JedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}"
p:port="${redis.port}"
p:password="${redis.pass}"
p:pool-config-ref="poolConfig"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
</beans>
- 5.建立TestString测试字符串操作方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestString {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSet() {
redisTemplate.boundValueOps("name").set("it");
}
@Test
public void testGet() {
String name = (String) redisTemplate.boundValueOps("name").get();
System.out.println("name=" + name);
}
@Test
public void testDelete() {
redisTemplate.delete("name");
}
}
- 6.建立TestList测试List操作方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestList {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testLpush() {
redisTemplate.boundListOps("myListKey").leftPush("001");
redisTemplate.boundListOps("myListKey").leftPush("002");
redisTemplate.boundListOps("myListKey").leftPush("003");
redisTemplate.boundListOps("myListKey").leftPush("004");
}
@Test
public void testRpush() {
redisTemplate.boundListOps("myListKey").rightPush("001");
redisTemplate.boundListOps("myListKey").rightPush("002");
redisTemplate.boundListOps("myListKey").rightPush("003");
redisTemplate.boundListOps("myListKey").rightPush("004");
}
@Test
public void testRange() {
List<String> myListKey = redisTemplate.boundListOps("myListKey").range(0, -1);
for (String s : myListKey) {
System.out.println("value=" + s);
}
}
@Test
public void testDelete() {
redisTemplate.delete("myListKey");
}
}
- 7.建立TestHash测试hash
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml"})
public class TestHash {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testPut() {
redisTemplate.boundHashOps("keyname1").put("name", "zs");
redisTemplate.boundHashOps("keyname1").put("age", "20");
redisTemplate.boundHashOps("keyname1").put("phone", "121");
redisTemplate.boundHashOps("keyname1").put("email", "1@qq.com");
}
@Test
public void testGetOne() {
String name = (String)redisTemplate.boundHashOps("keyname1").get("name");
System.out.println("name =" + name);
}
@Test
public void testGetAll() {
//获取所有的entries
Map<String, String> testHash = (Map<String, String>)redisTemplate.boundHashOps("keyname1").entries();
Set<Map.Entry<String, String>> entries = testHash.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println("key=" + entry.getKey());
System.out.println("value=" + entry.getValue());
}
}
@Test
public void testDeleteOne() {
redisTemplate.boundHashOps("keyname1").delete("name");
}
@Test
public void testDeleteAll() {
redisTemplate.delete("keyname1");
}
}
redis设置密码
进入redis命令模式(/usr/local/redis-4.0.9/6379/bin/redis-cli)
config set requirepass admin
auth admin
实例:使用redis缓存广告
- 1、添加redis依赖
<!-- Jackson Json处理工具包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.4</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
- 2、添加redis配置文件和属性文件
- redis-config.properties
redis.host=192.168.1.9
redis.port=6379
redis.pass=admin
redis.database=0
redis.maxIdle=300
redis.maxWait=3000
redis.testOnBorrow=true
-
- applicationContext-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath*:/properties/*.properties" />
<!-- redis 相关配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<bean id="JedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${redis.host}"
p:port="${redis.port}"
p:password="${redis.pass}"
p:pool-config-ref="poolConfig"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="JedisConnectionFactory" />
</bean>
</beans>
- 使用redis过程分析
- 获取数据的时候先从redis中获取,如果获取到数据则直接返回,就不用访问数据库了,
- 如果获取不到数据,可以从数据库中查询,查询到后放入redis中一份,下回就可以直接从redis中查询到,
这样大大降低了数据库的高并发访问压力。
- 查询分类广告方法
- 创建工具类统一管理 redis键
-
- redis数据存在结构:field为分类名称 value为分类下的广告
-
- 查询、修改、删除、更新分类广告服务层方法:
@Transactional
@Service
public class ContentServiceImpl implements ContentService {
@Autowired
private ContentDao contentDao;
@Autowired
private RedisTemplate redisTemplate;
@Override
public PageResult findPage(Content content, Integer page, Integer rows) {
PageHelper.startPage(page, rows);
ContentQuery query = new ContentQuery();
ContentQuery.Criteria criteria = query.createCriteria();
if (content != null) {
if (content.getTitle() != null && !"".equals(content.getTitle())) {
criteria.andTitleLike(content.getTitle()+"%");
}
}
Page<Content> contentList = (Page<Content>)contentDao.selectByExample(query);
return new PageResult(contentList.getTotal(), contentList.getResult());
}
@Override
public void add(Content content) {
/**
* 1. 将新广告添加到数据库中
*/
contentDao.insertSelective(content);
/**
* 2. 根据分类id, 到redis中删除对应分类的广告集合数据
*/
redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(content.getCategoryId());
}
@Override
public Content findOne(Long id) {
return contentDao.selectByPrimaryKey(id);
}
@Override
public void update(Content content) {
/**
* 1. 根据广告id, 到数据库中查询原来的广告对象
*/
Content oldContent = contentDao.selectByPrimaryKey(content.getId());
/**
* 2. 根据原来的广告对象中的分类id, 到redis中删除对应的广告集合数据
*/
redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(oldContent.getCategoryId());
/**
* 3. 根据传入的最新的广告对象中的分类id, 删除redis中对应的广告集合数据
*/
redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(content.getCategoryId());
/**
* 4. 将新的广告对象更新到数据库中
*/
contentDao.updateByPrimaryKeySelective(content);
}
@Override
public void delete(Long[] ids) {
if (ids != null) {
for (Long id : ids) {
/**
* 1. 根据广告id, 到数据库中查询广告对象
*/
Content content = contentDao.selectByPrimaryKey(id);
/**
* 2. 根据广告对象中的分类id, 删除redis中对应的广告集合数据
*/
redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).delete(content.getCategoryId());
/**
* 3. 根据广告id删除数据库中的广告数据
*/
contentDao.deleteByPrimaryKey(id);
}
}
}
@Override
public List<Content> findByCategoryId(long categoryId) {
ContentQuery query = new ContentQuery();
ContentQuery.Criteria criteria = query.createCriteria();
criteria.andCategoryIdEqualTo(categoryId);
List<Content> list = contentDao.selectByExample(query);
return list;
}
@Override
public List<Content> findByCategoryIdFromRedis(Long categoryId) {
/**
* 1. 首先根据分类id到redis中获取数据
*/
List<Content> contentList = (List<Content>)redisTemplate
.boundHashOps(Constants.CONTENT_LIST_REDIS)
.get(categoryId);
/**
* 2. 如果redis中没有数据则到数据库中获取数据
*/
if (contentList == null) {
/**
* 3. 如果数据库中获取到数据, 则放入redis中一份
*/
contentList = findByCategoryId(categoryId);
redisTemplate.boundHashOps(Constants.CONTENT_LIST_REDIS).put(categoryId, contentList);
}
return contentList;
}
}
-
- 控制层从redis中调用服务层取出数据
@RestController
@RequestMapping("/content")
public class ContentController {
@Reference
private ContentService contentService;
@RequestMapping("/findByCategoryId")
public List<Content> findByCategoryId(long categoryId){
return contentService.findByCategoryIdFromRedis(categoryId);
}
}