1、什么是redis?

在过去的几年中,NoSQL数据库一度成为高并发、海量数据存储解决方案的代名词,与之相应的产品也呈现出雨后春笋般的生机。然而在众多产品中能够脱颖而出的却屈指可数,如Redis、MongoDB、BerkeleyDB和CouchDB等。由于每种产品所拥有的特征不同,因此它们的应用场景也存在着一定的差异,下面仅给出简单的说明:
      1). BerkeleyDB是一种极为流行的开源嵌入式数据库,在更多情况下可用于存储引擎,比如BerkeleyDB在被Oracle收购之前曾作为MySQL的存储引擎,由此可以预见,该产品拥有极好的并发伸缩性,支持事务及嵌套事务,海量数据存储等重要特征,在用于存储实时数据方面具有极高的可用价值。然而需要指出的是,该产品的Licence为GPL,这就意味着它并不是在所有情况下都是免费使用的。
      2). 对MongoDB的定义为Oriented-Document数据库服务器,和BerkeleyDB不同的是该数据库可以像其他关系型数据库服务器那样独立的运行并提供相关的数据服务。从该产品的官方文档中我们可以获悉,MongoDB主要适用于高并发的论坛或博客网站,这些网站具有的主要特征是并发访问量高、多读少写、数据量大、逻辑关系简单,以及文档数据作为主要数据源等。和BerkeleyDB一样,该产品的License同为GPL。
      3). Redis,典型的NoSQL数据库服务器,和BerkeleyDB相比,它可以作为服务程序独立运行于自己的服务器主机。在很多时候,人们只是将Redis视为Key/Value数据库服务器,然而事实并非如此,在目前的版本中,Redis除了Key/Value之外还支持List、Hash、Set和Ordered Set等数据结构,因此它的用途也更为宽泛。对于此种误解,Redis官网也进行了相应的澄清。和以上两种产品不同的是,Redis的License是Apache License,就目前而言,它是完全免费。
      4). memcached,数据缓存服务器。为什么在这里要给出该产品的解释呢?很简单,因为笔者认为它在使用方式上和Redis最为相似。毕竟这是一篇关于Redis的技术系列博客,有鉴于此,我们将简要的对比一下这两个产品。首先说一下它们之间的最大区别,memcached只是提供了数据缓存服务,一旦服务器宕机,之前在内存中缓存的数据也将全部消失,因此可以看出memcached没有提供任何形式的数据持久化功能,而Redis则提供了这样的功能。再有就是Redis提供了更为丰富的数据存储结构,如Hash和Set。至于它们的相同点,主要有两个,一是完全免费,再有就是它们的提供的命令形式极为接近。
    
Redis的优势:

      1). 和其他NoSQL产品相比,Redis的易用性极高,因此对于那些有类似产品使用经验的开发者来说,一两天,甚至是几个小时之后就可以利用Redis来搭建自己的平台了。
      2). 在解决了很多通用性问题的同时,也为一些个性化问题提供了相关的解决方案,如索引引擎、统计排名、消息队列服务等。

目前版本中Redis存在的主要问题:

      1). 在官方版本中没有提供Windows平台的支持,已发布的正式版本中只是支持类Unix和MacOSX平台。
      2). 没有提供集群的支持,然而据官网所述,预计在2.6版本中会加入该特征。
      3). Publication/Subscription功能中,如果master宕机,slave无法自动提升为master。
    
和关系型数据库的比较:

      在目前版本(2.4.7)的Redis中,提供了对五种不同数据类型的支持,其中只有一种类型,既string类型可以被视为Key-Value结构,而其他的数据类型均有适用于各自特征的应用场景,至于具体细节我们将会在该系列后面的博客中予以说明。
      相比于关系型数据库,由于其存储结构相对简单,因此Redis并不能对复杂的逻辑关系提供很好的支持,然而在适用于Redis的场景中,我们却可以由此而获得效率上的显著提升。即便如此,Redis还是为我们提供了一些数据库应该具有的基础概念,如:在同一连接中可以选择打开不同的数据库,然而不同的是,Redis中的数据库是通过数字来进行命名的,缺省情况下打开的数据库为0。如果程序在运行过程中打算切换数据库,可以使用Redis的select命令来打开其他数据库,如select 1,如果此后还想再切换回缺省数据库,只需执行select 0即可。
      在数据存储方面,Redis遵循了现有NoSQL数据库的主流思想,即Key作为数据检索的唯一标识,我们可以将其简单的理解为关系型数据库中索引的键,而Value则作为数据存储的主要对象,其中每一个Value都有一个Key与之关联,这就好比索引中物理数据在数据表中存储的位置。在Redis中,Value将被视为二进制字节流用于存储任何格式的数据,如Json、XML和序列化对象的字节流等,因此我们也可以将其想象为RDB中的BLOB类型字段。由此可见,在进行数据查询时,我们只能基于Key作为我们查询的条件,当然我们也可以应用Redis中提供的一些技巧将Value作为其他数据的Key,这些知识我们都会在后面的博客中予以介绍。
    
如何持久化内存数据:(主从复制)

      缺省情况下,Redis会参照当前数据库中数据被修改的数量,在达到一定的阈值后会将数据库的快照存储到磁盘上,这一点我们可以通过配置文件来设定该阈值。通常情况下,我们也可以将Redis设定为定时保存。如当有1000个以上的键数据被修改时,Redis将每隔60秒进行一次数据持久化操作。缺省设置为,如果有9个或9个以下数据修改是,Redis将每15分钟持久化一次。
      从上面提到的方案中可以看出,如果采用该方式,Redis的运行时效率将会是非常高效的,既每当有新的数据修改发生时,仅仅是内存中的缓存数据发生改变,而这样的改变并不会被立即持久化到磁盘上,从而在绝大多数的修改操作中避免了磁盘IO的发生。然而事情往往是存在其两面性的,在该方法中我们确实得到了效率上的提升,但是却失去了数据可靠性。如果在内存快照被持久化到磁盘之前,Redis所在的服务器出现宕机,那么这些未写入到磁盘的已修改数据都将丢失。为了保证数据的高可靠性,Redis还提供了另外一种数据持久化机制--Append模式。如果Redis服务器被配置为该方式,那么每当有数据修改发生时,都会被立即持久化到磁盘。

2、为什么要使用redis? 

解决高并发的问题:

3   使用redis做缓存

3.1   安装redis

n  版本说明

本教程使用redis3.0版本。3.0版本主要增加了redis集群功能。

安装的前提条件:

需要安装gcc:yum install gcc-c++

1、下载redis的源码包。

2、把源码包上传到linux服务器

3、解压源码包

tar -zxvf redis-3.0.0.tar.gz

4、Make

5、Make install

[root@bogon redis-3.0.0]# make install PREFIX=/usr/local/redis

3.2   启动redis

1、前端启动模式

/usr/local/redis/bin/redis-server

默认是前端启动模式,端口是6379

2、后端启动

1)从redis的源码目录中复制redis.conf到redis的安装目录。

2)修改配置文件

3)[root@bogon bin]# ./redis-server redis.conf

3.3   Redis常用命令

127.0.0.1:6379> set a 10

OK

127.0.0.1:6379> get a

"10"

3.4   常用数据类型

String

Hash

List

Set

SortedSet

4   Redis集群的搭建

4.1   Redis集群相关概念

4.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.

4.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)错误

4.2   我们的集群结构

集群中有三个节点的集群,每个节点有一主一备。需要6台虚拟机。

搭建一个伪分布式的集群,使用6个redis实例来模拟。

4.3   搭建集群需要的环境

搭建集群需要使用到官方提供的ruby脚本。

需要安装ruby的环境。

安装ruby

yum install ruby

yum install rubygems

redis集群管理工具redis-trib.rb

[root@bogon ~]# cd redis-3.0.0

[root@bogon redis-3.0.0]# cd src

[root@bogon src]# ll *.rb

-rwxrwxr-x. 1 root root 48141 Apr  1 07:01 redis-trib.rb

[root@bogon src]#

脚本需要的ruby包:

需要上传到linux服务。

安装ruby的包:

gem install redis-3.0.0.gem

[root@bogon ~]# gem install redis-3.0.0.gem

Successfully installed redis-3.0.0

1 gem installed

Installing ri documentation for
redis-3.0.0...

Installing RDoc documentation for
redis-3.0.0...

4.4  
集群的搭建

第一步:创建6个redis实例,端口号从7001~7006

第二步:修改redis的配置文件

1、修改端口号

2、打开cluster-enable前面的注释。

第三步:把创建集群的ruby脚本复制到redis-cluster目录下。

第四步:启动6个redis实例

第五步:创建集群。

./redis-trib.rb create --replicas 1
192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003
192.168.25.153:7004 192.168.25.153:7005 
192.168.25.153:7006

[root@bogon redis-cluster]# ./redis-trib.rb
create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003
192.168.25.153:7004 192.168.25.153:7005 
192.168.25.153:7006

>>> Creating cluster

Connecting to node 192.168.25.153:7001: OK

Connecting to node 192.168.25.153:7002: OK

Connecting to node 192.168.25.153:7003: OK

Connecting to node 192.168.25.153:7004: OK

Connecting to node 192.168.25.153:7005: OK

Connecting to node 192.168.25.153:7006: OK

>>> Performing hash slots
allocation on 6 nodes...

Using 3 masters:

192.168.25.153:7001

192.168.25.153:7002

192.168.25.153:7003

Adding replica 192.168.25.153:7004 to
192.168.25.153:7001

Adding replica 192.168.25.153:7005 to
192.168.25.153:7002

Adding replica 192.168.25.153:7006 to
192.168.25.153:7003

M: 5a8523db7e12ca600dc82901ced06741b3010076
192.168.25.153:7001

slots:0-5460 (5461 slots) master

M: bf6f0929044db485dea9b565bb51e0c917d20a53
192.168.25.153:7002

slots:5461-10922 (5462 slots) master

M: c5e334dc4a53f655cb98fa3c3bdef8a808a693ca
192.168.25.153:7003

slots:10923-16383 (5461 slots) master

S: 2a61b87b49e5b1c84092918fa2467dd70fec115f
192.168.25.153:7004

replicates 5a8523db7e12ca600dc82901ced06741b3010076

S: 14848b8c813766387cfd77229bd2d1ffd6ac8d65
192.168.25.153:7005

replicates bf6f0929044db485dea9b565bb51e0c917d20a53

S: 3192cbe437fe67bbde9062f59d5a77dabcd0d632
192.168.25.153:7006

replicates c5e334dc4a53f655cb98fa3c3bdef8a808a693ca

Can I set the above configuration? (type
'yes' to accept): yes

>>> Nodes configuration updated

>>> Assign a different config
epoch to each node

>>> Sending CLUSTER MEET messages
to join the cluster

Waiting for the cluster to join.....

>>> Performing Cluster Check
(using node 192.168.25.153:7001)

M: 5a8523db7e12ca600dc82901ced06741b3010076
192.168.25.153:7001

slots:0-5460 (5461 slots) master

M: bf6f0929044db485dea9b565bb51e0c917d20a53
192.168.25.153:7002

slots:5461-10922 (5462 slots) master

M: c5e334dc4a53f655cb98fa3c3bdef8a808a693ca
192.168.25.153:7003

slots:10923-16383 (5461 slots) master

M: 2a61b87b49e5b1c84092918fa2467dd70fec115f
192.168.25.153:7004

slots: (0 slots) master

replicates 5a8523db7e12ca600dc82901ced06741b3010076

M: 14848b8c813766387cfd77229bd2d1ffd6ac8d65
192.168.25.153:7005

slots: (0 slots) master

replicates bf6f0929044db485dea9b565bb51e0c917d20a53

M: 3192cbe437fe67bbde9062f59d5a77dabcd0d632
192.168.25.153:7006

slots: (0 slots) master

replicates c5e334dc4a53f655cb98fa3c3bdef8a808a693ca

[OK] All nodes agree about slots
configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.

[root@bogon redis-cluster]#

4.5  
测试集群

[root@bogon redis-cluster]#
redis01/redis-cli -h 192.168.25.153 -p 7002 -c

 

 

[root@bogon redis-cluster]#
redis01/redis-cli -h 192.168.25.153 -p 7002

192.168.25.153:7002> set a 100

(error) MOVED 15495 192.168.25.153:7003

192.168.25.153:7002>

[root@bogon redis-cluster]#
redis01/redis-cli -h 192.168.25.153 -p 7002 -c

192.168.25.153:7002> set a 100

-> Redirected to slot [15495] located at
192.168.25.153:7003

OK

192.168.25.153:7003>

4.6  
关闭redis

redis01/redis-cli -p 7001 shutdown

4.7  
Redis客户端

4.7.1   Redis-cli

自带客户端。使用最多的。

4.7.2   图形化界面客户端

只支持单机版,不支持集群。

4.7.3   Jedis客户端

4.7.3.1        
单机版

需要把jedis的jar包添加到工程中,如果是maven需要添加jar包的坐标。

public class JedisTest {

@Test

public void testJedisSingle() {

//创建一个jedis的对象。

Jedis jedis = new Jedis("192.168.25.153", 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.25.153", 6379);

//从连接池中获得Jedis对象

Jedis jedis = pool.getResource();

String string = jedis.get("key1");

System.out.println(string);

//关闭jedis对象

jedis.close();

pool.close();

}

}

4.7.3.2        
集群版

@Test

public void testJedisCluster() {

HashSet<HostAndPort>
nodes = new
HashSet<>();

nodes.add(new HostAndPort("192.168.25.153", 7001));

nodes.add(new HostAndPort("192.168.25.153", 7002));

nodes.add(new HostAndPort("192.168.25.153", 7003));

nodes.add(new HostAndPort("192.168.25.153", 7004));

nodes.add(new HostAndPort("192.168.25.153", 7005));

nodes.add(new HostAndPort("192.168.25.153", 7006));

JedisCluster cluster = new JedisCluster(nodes);

cluster.set("key1", "1000");

String string = cluster.get("key1");

System.out.println(string);

cluster.close();

}

5   业务逻辑中添加缓存

需要在taotao-rest工程中添加缓存。

5.1  
jedis整合spring

5.1.1   单机版整合

5.1.1.1        
配置

<!-- 连接池配置
-->

<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.25.153"></constructor-arg>

<constructor-arg name="port" value="6379"></constructor-arg>

<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>

</bean>

5.1.1.2        
测试

/**

* 单机版测试

* <p>Title:
testSpringJedisSingle</p>

* <p>Description: </p>

*/

@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();

}

5.1.2   集群版整合

5.1.2.1        
配置

<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.25.153"></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.153"></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.153"></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.153"></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.153"></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.153"></constructor-arg>

<constructor-arg name="port" value="7006"></constructor-arg>

</bean>

</set>

</constructor-arg>

<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>

</bean>

5.1.2.2        
测试

@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();

}

5.2  
添加jedis dao

5.2.1   单机版

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;

}

}

Spring配置文件

5.2.2   集群版

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);

}

}

5.3  
把缓存添加到业务逻辑

注意:缓存的添加不能影响正常的业务逻辑。

@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;

}

课后作业:商品类目展示添加缓存

 

6   缓存同步

图中我们只需要在服务层写要同步的接口,然后后台或者服务层前来调用既可以同步。在后台的业务逻辑中,直接与数据库打交道,如果后台数据库的内容修改了,我们需要将缓存中的key值删除,然后重新写入缓存。这样就实现了缓存的同步。这个写的接口就在rest服务层,而调用rest都是采用的httpclient的方式。

当后台管理系统,修改内容之后需要通知redis把修改的内容对应的分类id的key删除。

6.1  
添加缓存后的系统架构

6.2  
解决方案

在taotao-rest工程中发布一个服务。当后台管理系统修改内容后,调用此服务,同步缓存。

6.3  
Dao层

使用JedisClient接口对应的实现类。

6.4  
Service层

接收内容分类id,调用dao删除redis中对应的hash中key为分类id的项。

参数:内容分类id

返回值:TaotaoResult

@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();

}

}

6.5  
Controller层

接收内容分类id,调用Service返回taotaoResult。

@Controller

@RequestMapping("/cache/sync")

public class RedisController
{

@Autowired

private RedisService redisService;

@RequestMapping("/content/{contentCid}")

public TaotaoResult
contentCacheSync(@PathVariable Long contentCid) {

TaotaoResult result = redisService.syncContent(contentCid);

return result;

}

}

6.6  
同步缓存服务的调用

需要在后台管理系统中添加一个服务调用的逻辑。当修改内容信息后,需要调用此服务同步缓存。

需要在哪个地方添加缓存,就先将数据存入缓存,然后再获取,

Redis之个人简单理解的更多相关文章

  1. Redis事务的简单理解

    Redis事务的命令如下所示: 先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令 示例如下: //开始一个事务 > MU ...

  2. Redis 安装与简单示例

    Redis 安装与简单示例 一.Redis的安装 Redis下载地址如下:https://github.com/dmajkic/redis/downloads 解压后根据自己机器的实际情况选择32位或 ...

  3. 【原创】分布式之数据库和缓存双写一致性方案解析(三) 前端面试送命题(二)-callback,promise,generator,async-await JS的进阶技巧 前端面试送命题(一)-JS三座大山 Nodejs的运行原理-科普篇 优化设计提高sql类数据库的性能 简单理解token机制

    [原创]分布式之数据库和缓存双写一致性方案解析(三)   正文 博主本来觉得,<分布式之数据库和缓存双写一致性方案解析>,一文已经十分清晰.然而这一两天,有人在微信上私聊我,觉得应该要采用 ...

  4. redis安装及简单使用

    前言 一般企业级开发,数据库用的都是关系型数据库Mysql.Oracle及SqlServer.无一例外,在开发过程中,我们都必须通过数据库驱动来连接到数据库,之后才可以完成对数据库的增删改查等业务.而 ...

  5. Redis(八)理解内存

    Redis所有的数据都存在内存中,当前内存虽然越来越便宜,但跟廉价的硬盘相比成本还是比较昂贵,因此如何高效利用Redis内存变得非常重要. 高效利用Redis内存首先需要理解Redis内存消耗在哪里, ...

  6. git的简单理解及基础操作命令

    前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...

  7. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  8. [转]简单理解Socket

    简单理解Socket 转自 http://www.cnblogs.com/dolphinX/p/3460545.html  题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公 ...

  9. Redis中的简单事物以及消息订阅发布

    Redis支持简单的事物,但是没有mysql的Innodb支持的那么的完善 我们接下来看一下Redis和Mysql的事物的一个对比:   MySQL Redis 开启 start transactio ...

随机推荐

  1. python进行mp3格式判断

    python进行mp3格式判断 项目中使用mp3格式进行音效播放,遇到一个mp3文件在程序中死活播不出声音,最后发现它是wav格式的文件,却以mp3结尾.要对资源进行mp3格式判断,那么如何判断呢,用 ...

  2. 15-static和extern关键字1-对函数的作用

    一.extern与函数 如果一个程序中有多个源文件(.c),编译成功会生成对应的多个目标文件(.obj),这些目标文件还不能单独运行,因为这些目标文件之间可能会有关联,比如a.obj可能会调用c.ob ...

  3. 软件工程随笔(1)--jetbrain在软件工程中的应用

    接下来几天我要写半年的软件工程学习后的感想,今天从介绍IDE开始.首先,本人至今为止全部项目都是在mypclise上完成的.本人采用myeclipse唯一的原因就是它使用方便.但是,我也承认myecl ...

  4. 关于case语句中声明变量并初始化的注意事项

    今天看到一句对这个问题特别精辟的总结,记录如下: It is possible to transfer into a block, but not in a way that bypasses dec ...

  5. 在VMware上安装Linux(CentOS)

    1. 新建虚拟机 2. 新建虚拟机向导 3. 创建虚拟空白光盘 4. 安装Linux系统对应的CentOS版 5. 虚拟机命名和定位磁盘位置 6. 处理器配置,看自己是否是双核.多核 7. 设置内存为 ...

  6. SQL Server 进阶 01 数据库的设计

    SQL Server 进阶 01 数据库的设计 本篇目录 课程内容回顾及介绍 为什么需要规范的数据库设计 设计数据库的步骤 绘制E-R(实体-关系)图 实体-关系模型 如何将E-R图转换为表 数据规范 ...

  7. Spring:Aop before after afterReturn afterThrowing around 的原理

    在写这篇文章前,在网上看了一下大多数的文章,在说这一块时,都是用语言来表达的.before.after.afterReturn.afterThrowing 这四个用语言是可以说清楚的,但 around ...

  8. 4-3 管理及IO重定向

    1. 系统设定默认输出设备:标准输出(STDOUT,1) 系统设定默认输入设备:标准输入(STDIN,0) 系统设定默认错误设备:标准错误(STDERR,2) 2. 标准输入:键盘 标准输出和错误输出 ...

  9. Django 前后台的数据传递

    Django 从后台往前台传递数据时有多种方法可以实现. 最简单的后台是这样的: from django.shortcuts import render def main_page(request): ...

  10. django 一些相关问题

    这两天在处理django项目时碰到一些问题 1.ur路径设置要忽略大小写,查找了很多资料,都没有发现相关的介绍,最后在谷歌上找到一个解决方案,https://groups.google.com/for ...