redis缓存一般用于集群共享信息,而spring+ehcache缓存一般用于增删改查用,都是缓存用法不同而已。
redis的三大用法:
1 主从复制,持久化机制(都是在redis.properties这个文件里面)(saleof,一个主服务器master可以同步多个从服务器salve,注意不是客户端)
2 集群
3 缓存
后续主攻方向:增删改查时候的缓存该如何设置
一:主从复制,持久化机制(redis.conf添加几个指令就可以实现这种功能)
redis的持久化机制(也就是把内存中的内容存到数据库硬盘中),redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化。
redis支持两种持久化方式,一种是 Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。下面分别介绍Snapshotting快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久 化的方式。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置.
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000
Redis 的 master/slave 数据复制方式可以是一主一从或者是一主多从的方式,Redis 在master 是非阻塞模式,也就是说在 slave 执行数据同步的时候,master 是可以接受客户端的请求的,并不影响同步数据的一致性,然而在 slave 端是阻塞模式的,slave 在同步 master数据时,并不能够响应客户端的查询 Redis 的 master/slave 模式下,master 提供数据读写服务,而 slave 只提供读服务 Redis 的 master/slave 的配置方式是在 slave 主机的 Redis 目录下的 redis.conf 配置文件中添加: slaveof master_ip master_port
二:集群(application.xml配置文件配置3个bean文件就可以了)
Redis 的主从复制技术,当实现了多节点的 master-slave 后,我们也可以把它叫做集群,但我们今天要讲的集群主要是利用切片技术来组建的集群。redis作为集群时,一定要配置3bean: jedisPoolConfig,jedisConnectionFactory, redisTemplate(写的主服务器的地址及端口)由于配置中有一条 从服务器 是只读的,所以从服务器slave 没法设置数据,只可以读取数据。
三:缓存(封装它的命令方法)
分为自定义缓存和@cacheable注解缓存两种形式,使用@cacheable注解进行增删改缓存时,要注意的两个地方:自定义缓存数据 key 生成策略和缓存数据一致性保证
redis作为缓存时,比如jedis.exists这个方法中,exists这个方法就是jedis实例中连接的方法。我只需要每一个方法都连接一个jedis,并写出这个jedis对应的指令方法即可。这就叫封装一个公用方法。然后把这个集合了多个jedis公共方法的bean写到application.xml文件里面(暂且叫这个bean为A吧),
然后在其他bean中用的时候,直接这样使用就好了。
<bean id="B" class="com...B">
<property name="A" ref="A" />
</bean>
一定要注意的是在写B这个方法的时候,A一定要作为一个引入的service,写入,然后就可以在B中调用A的各种缓存处理方法
广泛应用于集群权限控制,会话,数据库增删改查中。
redis命令行问题一般用于缓存处理。
特别注意的是:要缓存的 Java 对象必须实现 Serializable 接口
redis学习手册中 有多种数据类型,每一种数据类型的操作命令都不太一样,但是不直接支持javaBean类型,这个时候需要用到序列化了,最为常见的就是map,其数据类型为Hashes类型,最多允许三个参数:key、field和value。
看了看Redis的API,很多都是放字符串进去。java对象想放进入还要序列化,拿出来还要反序列化。感觉好麻烦。其实我一直不明白,java把对象从内存放到硬盘为啥需要序列化。内存跟硬盘有什么不一样吗?能不能把对象用fastJSON转成JSON字符串放到Redis,拿出来再解析为对象。这两种搞法效率哪个高?请大家谈谈想法。 redis虽然提供了对list set hash等数据类型的支持,但是没有提供对POJO对象的支持,底层都是把对象序列化后再以字符串的方式存储的。因此,Spring data提供了若干个Serializer,主要包括: JacksonJsonRedisSerializer、JdkSerializationRedisSerializer、OxmSerializer。需要序列化,主要是一种针对需要I/O操作的,此时写入磁盘恰巧需要I/O。让类实现serializable接口,此类的对象就可以被序列化了。针对对象的对象流:ObjectOutputStream,调用writeObject()/readObject()可以实现序列化、反序列化。
----------------------------------------------------------------------------------------------------
首先,我们给一个服务配置Cache,如下:
@Service('helloService') public class HelloServiceImpl implements HelloService { /** * Using SpEL for conditional caching - only cache method executions when * the name is equal to 'Joshua' */ @Cacheable(value='messageCache', condition=''Joshua'.equals(#name)') public String getMessage(String name) { System.out.println('Executing HelloServiceImpl' + '.getHelloMessage(\'' + name + '\')'); return 'Hello ' + name + '!'; } }
JedisConnectionFactory 有以下参数: ◾hostName=”localhost” ◾port=6379 ◾timeout=2000 ms ◾database=0 ◾usePool=true
<?xml version='1.0' encoding='UTF-8'?> <beans xmlns='http://www.springframework.org/schema/beans' <!-- 这个是用来扫描action类和加载属性文件,这个具有很强的示范意义--> <context:component-scan base-package='com.joshuawhite.example.service' /> <context:property-placeholder location='classpath:/redis.properties'/> <!-- 这个是用来开启Spring缓存配置的--> <cache:annotation-driven /> <!-- Jedis ConnectionFactory --> <bean id='jedisConnectionFactory' class='org.springframework.data.redis.connection.jedis.JedisConnectionFactory' p:host-name='${redis.host-name}' p:port='${redis.port}' p:use-pool='true'/> <!-- redis template definition --> <bean id='redisTemplate' class='org.springframework.data.redis.core.RedisTemplate' p:connection-factory-ref='jedisConnectionFactory'/> <!-- declare Redis Cache Manager --> <bean id='cacheManager' class='org.springframework.data.redis.cache.RedisCacheManager' c:template-ref='redisTemplate'/> </beans>
下面是客户端调用代码:
public class App { @Resource private HelloService helloService; public static void main(String[] args) { //First method execution using key='Josh', not cached System.out.println('message: ' + helloService.getMessage('Josh')); //Second method execution using key='Josh', still not cached System.out.println('message: ' + helloService.getMessage('Josh')); //第一次执行肯定不会执行缓存 System.out.println('message: ' + helloService.getMessage('Joshua')); //第二次再执行肯定回走缓存的 System.out.println('message: ' + helloService.getMessage('Joshua')); } }
Executing HelloServiceImpl.getHelloMessage('Josh') message: Hello Josh! Executing HelloServiceImpl.getHelloMessage('Josh') message: Hello Josh! Executing HelloServiceImpl.getHelloMessage('Joshua') message: Hello Joshua! Executing HelloServiceImpl.getHelloMessage('Joshua') message: Hello Joshua!