Redis之个人简单理解

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

[[email protected] 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)[[email protected] 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

[[email protected] ~]# cd redis-3.0.0

[[email protected] redis-3.0.0]# cd src

[[email protected] src]# ll *.rb

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

[[email protected] src]#

脚本需要的ruby包:

需要上传到linux服务。

安装ruby的包:

gem install redis-3.0.0.gem

[[email protected] ~]# 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

[[email protected] 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.

[[email protected] redis-cluster]#

4.5  
测试集群

[[email protected] redis-cluster]#
redis01/redis-cli -h 192.168.25.153 -p 7002 -c

 

 

[[email protected] 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>

[[email protected] 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  
同步缓存服务的调用

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

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

时间: 2024-10-12 17:39:05

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

Redis 安装与简单示例

Redis 安装与简单示例 一.Redis的安装 Redis下载地址如下:https://github.com/dmajkic/redis/downloads 解压后根据自己机器的实际情况选择32位或者64位.下载解压后图片如下: redis-server.exe redis服务器的daemon启动程序 redis.conf redis配置文件 redis-cli.exe redis命令行操作工具.当然,也可以用telnet根据其纯文本协议来操作 redis-check-dump.exe 本地数

redis安装及简单使用

前言 一般企业级开发,数据库用的都是关系型数据库Mysql.Oracle及SqlServer.无一例外,在开发过程中,我们都必须通过数据库驱动来连接到数据库,之后才可以完成对数据库的增删改查等业务.而本文将和大家共同分享学习一下redis这种高性能的key-value数据库,也通常被大家称为内存高速缓存数据库. 一.ubuntu下安装启动 1.安装 2.启动 3.查看是否启动成功 二.redis数据类型 Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),se

redis消息队列简单应用

参考 https://blog.yxccan.cn/blog/detail/3 一.什么是消息队列 是一个消息的链表,是一个异步处理的数据处理引擎. PS:可以理解为在redis的list列表中存放消息数据,然后按照排队方式先进先出(左进右出:右进左出) 二.可以使用的应用场景 主要应用一些延迟或异步操作的场景比如:发送邮件.发送短信.视频转码.图片转码.日志存储.导入数据等在发送邮件或者短信,我们不希望程序一直停留,等待发送成功才相应,而是异步进行处理,即:将待发送的邮件数据添加到消息队列中,

php类的封装、继承和多态的简单理解

.面象对向的三大特点:封装性.继承性.多态性 首先简单理解一下抽象: 我们在前面定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象 一.封装性  封装就是把抽取出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有被授权的操作(方法)才能对数据进行操作.  php提供了三种访问控制修饰符  public 表示全局,本类内部,类外部,子类都可以访问  protected 表示受保护的,只有本类或子类可以访问  pr

简单理解计算机通信

简单理解计算机通信 写在前面: 在计算机刚出现的时候,只能在本机进行一些运算处理,想将一台计算机中的数据转移到另一台计算机中,需要通过外部存储介质来传输,例如磁带.软盘.而网络技术的出现,使得计算机间可以通过一些传输介质(网线.光纤等),实现快速的数据传输和信息交互.如今,网络已无处不在,那么,计算机之间究竟是如何通信的呢?下面会通过一些基础的网络知识来简单理解计算机之间的通信过程. 网络通信模型: 网络通信模型是一种概念模型和框架,旨在使各种计算机在世界范围内互连为网络.其中有OSI七层模型和

Http协议与TCP协议简单理解

在C#编写代码,很多时候会遇到Http协议或者TCP协议,这里做一个简单的理解. TCP协议对应于传输层,而HTTP协议对应于应用层,从本质上来说,二者没有可比性.Http协议是建立在TCP协议基础之上的,当浏览器需要从服务器获取网页数据的时候,会发出一次Http请求.Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的.所以Http连接是一种短连接,是一种无状态的连接.所谓的无状态,是指浏览器每次向服务器发起请求的时候,

Redis安装及简单测试

题目链接:11645 - Bits 题意:给定一个数字n,要求0-n的二进制形式下,连续11的个数. 思路:和 UVA 11038 这题类似,枚举中间,然后处理两边的情况. 不过本题最大的答案会超过longlong,要用高精度,不过借鉴http://www.cnblogs.com/TO-Asia/p/3214706.html这个人的方法,直接用两个数字来保存一个数字,这样能保存到2个longlong的长度,就足够存放这题的答案了. 代码: #include <stdio.h> #include

回溯法之八皇后问题简单理解

回溯法,简单理解就是有源可溯.基本思想要借鉴穷举法,但是它不是一味地穷举,当发现某一步不符合条件时,这一步后面的穷举操作就不进行了(俗称“剪枝”),我自己把它叫做动态穷举法.假设第一个步骤可行,那么执行第二个步骤,第三个......如果其中第三个步骤不行,那么我们再回过来(回溯),第二个步骤换一种方法尝试,然后再重新第三个步骤,第四个......直到完成任务要求为止. 这里,以八皇后问题为例.试图把回溯法讲清楚. 注意:递归应该是一种算法结构,回溯法是一种算法思想. 何为八皇后问题? (百度百科

Javascript闭包简单理解

提到闭包,想必大家都早有耳闻,下面说下我的简单理解.说实话平时工作中实际手动写闭包的场景并不多,但是项目中用到的第三方框架和组件或多或少用到了闭包.所以,了解闭包是非常必要的.呵呵... 一.什么是闭包简而言之,就是能够读取其他函数内部变量的函数.由于JS变量作用域的特性,外部不能访问内部变量,内部可以外部变量. 二.使用场景1. 实现私有成员.2. 保护命名空间,避免污染全局变量.3. 缓存变量. 先看一个封装的例子: var person = function () { // 变量作用域为函