SpringCache学习之操作redis
一、redis快速入门
1、redis简介
在java领域,常见的四大缓存分别是ehcache,memcached,redis,guava-cache,其中redis与其他类型缓存相比,有着得天独厚的优势:
- 它是基于内存的数据库,什么意思呢?由于受磁盘IO影响,它所有操作都在内存当中,用以提高性能,同时采用异步的方式将数据保存在硬盘当中。
- 与memcached相比,redis支持多种数据类型,string,list,set,sorted set,hash。让我们使用起来更加灵活
- 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
- 丰富的特性:可用于缓存,消息,可以设置key的过期时间,过期后将会自动删除对应的记录
- redis是单线程单进程的,它利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
2、redis常见的数据类型
2.1 redis的key:
我们可以使用任何二进制序列当我们的键,过长过短的键都不建议使用,在这里建议大家使用尝试使用一个模式。例如,“object-type:id”是一个比较推荐的方式,举个例子,我们可以这样来定义键:“user:1000”。点或破折号通常用于多字字段。
2.2 strings: 该类型是最基本的数据类型,也是最常见的数据类型。我们可以使用set 或get 来设置和获取对应的值:
> set mykey somevalue
OK
> get mykey
"somevalue"
在这里面set 如果已经存在的key 会替换已有的值。注意value的值不要大于512M
另外,我们可以使用mset 与 mget来设置和获取多个值,如下:
> mset a b c
OK
> mget a b c
) ""
) ""
) ""
我们可以使用exists判断key对应的值是否存在,del则是删除key对应的值
> set mykey hello
OK
> exists mykey
(integer)
> del mykey
(integer)
> exists mykey
(integer)
我们也可以指定key值对应的过期时间:(单位为秒)
> set key some-value
OK
> expire key
(integer)
> get key (immediately)
"some-value"
> get key (after some time)
(nil)
2.3 lists类型:这个类似于我们的集合类型,可以存放多个值,我们可以使用lpush(在头部添加)与rpush(在尾部添加)来添加对应的元素:
rpush mylist A
(integer)
> rpush mylist B
(integer)
> lpush mylist first
(integer)
> lrange mylist -
) "first"
) "A"
) "B"
其中lrange 是取一定范围的元素
2.4 Hashes 这个类似于key->key ,value的形式,我们可以使用hmset与hget来取值
> hmset user: username antirez birthyear verified
OK
> hget user: username
"antirez"
> hget user: birthyear
""
> hgetall user:
) "username"
) "antirez"
) "birthyear"
) ""
) "verified"
) ""
2.5、SETS:存放了一系列无序的字符串集合,我们可以通过sadd与smembers来取值:
> sadd myset
(integer)
> smembers myset
.
.
.
3、redis中的事务
MULTI 命令用于开启一个事务,它总是返回 OK
。 MULTI执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。redis中事务不存在回滚,我们这么操作试试:
localhost:>multi
"OK" localhost:>set test abc
"QUEUED" localhost:>incr test
"QUEUED" localhost:>exec
) "OK"
) "ERR value is not an integer or out of range"
localhost:>get test
"abc"
如果事务当中入队不成功,我们可以看一下例子:
localhost:>multi
"OK" localhost:>set test abcd
"QUEUED" localhost:>test abc
"ERR unknown command 'test'" localhost:>exec
"EXECABORT Transaction discarded because of previous errors." localhost:>get test
"abc"
此时就会终止我们提交事务
另外我们调用 DISCARD , 客户端可以清空事务队列并放弃执行事务。例子:
localhost:>multi
"OK" localhost:>set test abcd
"QUEUED" localhost:>discard
"OK" localhost:>get test
"abc"
4、远程连接redis注意事项
redis现在的版本开启redis-server后,redis-cli只能访问到127.0.0.1,因为在配置文件中固定了ip,因此需要修改redis.conf(有的版本不是这个文件名,只要找到相对应的conf后缀的文件即可)文件以下几个地方。1、bind 127.0.0.1改为 #bind 127.0.0.1 2、protected-mode yes 改为 protected-mode no
指定配置文件运行:
./redis-server ../redis.conf
远程连接的命令:
./redis-cli -p -h xxx.xxx.xxx
二、使用SpringCache集成redis
1、关于SpringCache
从SpringFramework3.1版本开始,Spring给我们提供了一系列注解和接口规范来简化我们操作缓存代码量,几个核心接口如下:
CacheManager: 该接口主要作用是获取缓存和获取缓存名称
/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.cache; import java.util.Collection; import org.springframework.lang.Nullable; /**
* Spring's central cache manager SPI.
* Allows for retrieving named {@link Cache} regions.
*
* @author Costin Leau
* @since 3.1
*/
public interface CacheManager { /**
* Return the cache associated with the given name.
* @param name the cache identifier (must not be {@code null})
* @return the associated cache, or {@code null} if none found
*/
@Nullable
Cache getCache(String name); /**
* Return a collection of the cache names known by this manager.
* @return the names of all caches known by the cache manager
*/
Collection<String> getCacheNames(); }
在这里面最核心的接口当然是Cache:
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.cache; import java.util.concurrent.Callable; import org.springframework.lang.Nullable; /**
* Interface that defines common cache operations.
*
* <b>Note:</b> Due to the generic use of caching, it is recommended that
* implementations allow storage of <tt>null</tt> values (for example to
* cache methods that return {@code null}).
*
* @author Costin Leau
* @author Juergen Hoeller
* @author Stephane Nicoll
* @since 3.1
*/
public interface Cache { /**
* Return the cache name.
*/
String getName(); /**
* Return the underlying native cache provider.
*/
Object getNativeCache(); /**
* Return the value to which this cache maps the specified key.
* <p>Returns {@code null} if the cache contains no mapping for this key;
* otherwise, the cached value (which may be {@code null} itself) will
* be returned in a {@link ValueWrapper}.
* @param key the key whose associated value is to be returned
* @return the value to which this cache maps the specified key,
* contained within a {@link ValueWrapper} which may also hold
* a cached {@code null} value. A straight {@code null} being
* returned means that the cache contains no mapping for this key.
* @see #get(Object, Class)
*/
@Nullable
ValueWrapper get(Object key); /**
* Return the value to which this cache maps the specified key,
* generically specifying a type that return value will be cast to.
* <p>Note: This variant of {@code get} does not allow for differentiating
* between a cached {@code null} value and no cache entry found at all.
* Use the standard {@link #get(Object)} variant for that purpose instead.
* @param key the key whose associated value is to be returned
* @param type the required type of the returned value (may be
* {@code null} to bypass a type check; in case of a {@code null}
* value found in the cache, the specified type is irrelevant)
* @return the value to which this cache maps the specified key
* (which may be {@code null} itself), or also {@code null} if
* the cache contains no mapping for this key
* @throws IllegalStateException if a cache entry has been found
* but failed to match the specified type
* @since 4.0
* @see #get(Object)
*/
@Nullable
<T> T get(Object key, @Nullable Class<T> type); /**
* Return the value to which this cache maps the specified key, obtaining
* that value from {@code valueLoader} if necessary. This method provides
* a simple substitute for the conventional "if cached, return; otherwise
* create, cache and return" pattern.
* <p>If possible, implementations should ensure that the loading operation
* is synchronized so that the specified {@code valueLoader} is only called
* once in case of concurrent access on the same key.
* <p>If the {@code valueLoader} throws an exception, it is wrapped in
* a {@link ValueRetrievalException}
* @param key the key whose associated value is to be returned
* @return the value to which this cache maps the specified key
* @throws ValueRetrievalException if the {@code valueLoader} throws an exception
* @since 4.3
*/
@Nullable
<T> T get(Object key, Callable<T> valueLoader); /**
* Associate the specified value with the specified key in this cache.
* <p>If the cache previously contained a mapping for this key, the old
* value is replaced by the specified value.
* @param key the key with which the specified value is to be associated
* @param value the value to be associated with the specified key
*/
void put(Object key, @Nullable Object value); /**
* Atomically associate the specified value with the specified key in this cache
* if it is not set already.
* <p>This is equivalent to:
* <pre><code>
* Object existingValue = cache.get(key);
* if (existingValue == null) {
* cache.put(key, value);
* return null;
* } else {
* return existingValue;
* }
* </code></pre>
* except that the action is performed atomically. While all out-of-the-box
* {@link CacheManager} implementations are able to perform the put atomically,
* the operation may also be implemented in two steps, e.g. with a check for
* presence and a subsequent put, in a non-atomic way. Check the documentation
* of the native cache implementation that you are using for more details.
* @param key the key with which the specified value is to be associated
* @param value the value to be associated with the specified key
* @return the value to which this cache maps the specified key (which may be
* {@code null} itself), or also {@code null} if the cache did not contain any
* mapping for that key prior to this call. Returning {@code null} is therefore
* an indicator that the given {@code value} has been associated with the key.
* @since 4.1
*/
@Nullable
ValueWrapper putIfAbsent(Object key, @Nullable Object value); /**
* Evict the mapping for this key from this cache if it is present.
* @param key the key whose mapping is to be removed from the cache
*/
void evict(Object key); /**
* Remove all mappings from the cache.
*/
void clear(); /**
* A (wrapper) object representing a cache value.
*/
@FunctionalInterface
interface ValueWrapper { /**
* Return the actual value in the cache.
*/
@Nullable
Object get();
} /**
* Wrapper exception to be thrown from {@link #get(Object, Callable)}
* in case of the value loader callback failing with an exception.
* @since 4.3
*/
@SuppressWarnings("serial")
class ValueRetrievalException extends RuntimeException { @Nullable
private final Object key; public ValueRetrievalException(@Nullable Object key, Callable<?> loader, Throwable ex) {
super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex);
this.key = key;
} @Nullable
public Object getKey() {
return this.key;
}
} }
该接口定义了操作缓存的最基本行为
同时Spring给我们提供了一些默认的缓存实现 比如说:JDK java.util.concurrent.ConcurrentMap,
ehcache2.x , Gemfire cache, guava等
2、几个重要的注解
@EnableCaching:用于开启缓存注解,通常需要和@Configuration使用
@Cacheable
该注解的意思为:读缓存中的值,如果没有该值,那么将执行注解对应的方法并将方法返回结果存入缓存
使用示例:
@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
有些时候我们希望根据条件将对应数据存入缓存,可以这么写:
@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback")
public Book findBook(String name)
示例中:condition条件为true时,才存入缓存,unless属性是针对本次查询结果筛选。注意当表达式为true时的结果都不会存入缓存, #result 代表了方法的返回结果
@CacheEvict
触发Cache接口中的evict方法,相当于移除key对应的值
@CacheEvict(cacheNames="books", allEntries=true,beforeInvocation=true)
public void loadBooks(InputStream batch)
beforeInvocation属性表明是否在执行方法之前清除缓存,allEntries属性会删除缓存下的所有数据,另外如果该值为true时就不能和key同时使用了
@CachePut
执行方法并更新缓存
@CachePut(cacheNames="book", key="#isbn")
public Book updateBook(ISBN isbn, BookDescriptor descriptor)
这些缓存注解的幕后英雄当然是我们的AOP啦
3、缓存注解中的SpringEL表达式
springEL可以运用在我们的cache注解当中,比如说其中key属性 condition属性等,其中#result只能在unless属性中使用这点比较特殊,在这里我贴出官网的列表:
Description | Example |
---|---|
The name of the method being invoked |
|
The method being invoked |
|
The target object being invoked |
|
The class of the target being invoked |
|
The arguments (as array) used for invoking the target |
|
Collection of caches against which the current method is executed |
|
Name of any of the method arguments. If for some reason the names are not available (e.g. no debug information), the argument names are also available under the |
|
The result of the method call (the value to be cached). Only available in |
|
4、代码集成示例
该代码是基于spring与hibernate集成,请参考:这里
gradle配置:
compile 'org.springframework.data:spring-data-redis:2.0.6.RELEASE' // https://mvnrepository.com/artifact/redis.clients/jedis
compile group: 'redis.clients', name: 'jedis', version: '2.9.0' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.5' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.5'
1.创建RedisConfig:
package com.bdqn.lyrk.ssh.study.config; import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext; @Configuration
@EnableCaching
public class RedisConfig { /**
* 创建redisConnectionFactory
* @return
*/
@Bean
public RedisConnectionFactory redisConnectionFactory() {
/*
设置相关配置
*/
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setPort(6379);
configuration.setHostName("localhost");
configuration.setDatabase(0);
JedisConnectionFactory jedisConnectionFactory =
new JedisConnectionFactory(configuration);
return jedisConnectionFactory;
} @Bean
public StringRedisTemplate stringRedisTemplate() {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(redisConnectionFactory());
return stringRedisTemplate;
} @Bean
public RedisCacheManager cacheManager() {
/*
配置json序列化方式
*/
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().
serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(redisConnectionFactory()).
transactionAware().cacheDefaults(cacheConfiguration).build();
}
}
2.创建StudentService
package com.bdqn.lyrk.ssh.study.service; import com.bdqn.lyrk.ssh.study.entity.StudentEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; @Service
public class StudentService { @Autowired
private HibernateTemplate hibernateTemplate; @Transactional
public int save(StudentEntity studentEntity) {
hibernateTemplate.save(studentEntity);
return studentEntity.getId();
} @Cacheable(key = "#id", cacheNames = "student", cacheManager = "cacheManager", condition = "#id==1")
public StudentEntity listStudents(Integer id) {
return hibernateTemplate.get(StudentEntity.class, id);
} @Transactional
@CachePut(key = "#id", cacheNames = "student", cacheManager = "cacheManager")
public StudentEntity updateStudent(Integer id) {
StudentEntity studentEntity = new StudentEntity();
studentEntity.setId(id);
studentEntity.setStuName("tests");
studentEntity.setPassword("password");
hibernateTemplate.update(studentEntity);
return studentEntity;
} @CacheEvict(key = "#id", cacheNames = "student")
@Transactional
public StudentEntity deleteStudent(Integer id) {
StudentEntity studentEntity = hibernateTemplate.load(StudentEntity.class, id);
hibernateTemplate.delete(studentEntity);
return studentEntity;
}
}
3.Main方法:
package com.bdqn.lyrk.ssh.study; import com.bdqn.lyrk.ssh.study.config.AppConfig;
import com.bdqn.lyrk.ssh.study.service.StudentService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
StudentService studentService =
applicationContext.getBean(StudentService.class);
studentService.updateStudent(1);
System.out.println(studentService.listStudents(1).getStuName());
studentService.deleteStudent(1);
}
}
运行结果:
我们可以看到:第二次查询时并没有输出Hibernate的执行的sql,说明这个是从redis缓存中读取的。
SpringCache学习之操作redis的更多相关文章
- 尚硅谷redis学习11-jedis操作redis
前面学习了redis的知识后,下面学习一下如何在java中通过jedis操作redis. 所需jar包:commons-pool-xxxx.jar,jedis-xxx.jar 下面看一下常用操作: 1 ...
- Python学习之==>操作Redis
一.redis简介 1.非关系型数据库 2.数据全部是存在内存里面 3.性能非常好,每秒支持30w次读写 4.可以通过备份数据库,把数据存到磁盘上来实现数据的持久化 二.操作redis 1.strin ...
- python学习之操作redis
一.Redis安装网上很多可以查找 二.redis-py的安装,使用命令pip install redis. 安装过程中如果产生连接超时的错误,可以使用国内镜像参考如下 豆瓣:pip install ...
- Python基础学习六 操作Redis
import redis r = redis.Redis(host=',db=1) #set get delete setex 都是针对string类型的 k-v # r.set('louis_ses ...
- 二、redis学习(java操作redis缓存的工具jedis)
- Python操作redis学习系列之(集合)set,redis set详解 (六)
# -*- coding: utf-8 -*- import redis r = redis.Redis(host=") 1. Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合 ...
- redis学习 (key)键,Python操作redis 键 (二)
# -*- coding: utf-8 -*- import redis #这个redis 连接不能用,请根据自己的需要修改 r =redis.Redis(host=") 1. delete ...
- Python学习笔记(五)之Python操作Redis、mysql、mongodb数据库
操作数据库 一.数据库 数据库类型主要有关系型数据库和菲关系型数据库. 数据库:用来存储和管理数的仓库,数据库是通过依据“数据结构”将数据格式化,以记录->表->库的关系存储.因此数据查询 ...
- Python进阶学习_连接操作Redis数据库
安装导入第三方模块Redis pip3 install redis import redis 操作String类型 """ redis 基本命令 String set(n ...
随机推荐
- java 1.7新特性
try( ... ){ ... } catch(xxx e){ ... } java1.7特性,叫做try-with-resource,实现了AutoCloseable接口的实例可以放在try(... ...
- PHP环境手动搭建wamp-----Apache+MySQL+PHP
首先下载分别下载Apache+MySQL+PHP. 然后分别解压到文件夹中. 1.安装Apache 1)检查80端口是否占用 说明:apache软件占用80软件,在计算机中一个端口只能被一个软件占用 ...
- Table点击某个td获取当前列的头名称
jq代码: $("td").click(function () { var tdHtml = $(this).attr("html"); var index = ...
- Python爬虫基本原理
爬虫基本原理 1. 什么是爬虫 请求网站并提取数据的自动化程序. 2. 爬虫基本流程 发起请求 通过HTTP库向目标站点发起请求,即发送一个Request,请求可以包含额外的headers等信息,等待 ...
- 多台linux主机之间建立免密通信
多台linux主机之间设置免密通信 例:A 向 B设置免密通信 第一步 A生成密钥对 ssh-keygen -t rsa -t 指定秘钥的类型 rsa 秘钥类型 密钥目录:/root/.ssh/(如果 ...
- jmeter入门(02)测试报告各项指标含义
一.名词定义(时间单位ms) 1.聚合报告 Sample:本次测试场景共运行多少个请求: Average:平均响应时间: Median:统计意义上的响应时间中值: 90% line:所有线程中90%的 ...
- GIT入门笔记(16)- 分支创建和管理
查看分支:git branch创建分支:git branch <name>切换分支:git checkout <name>创建+切换分支:git checkout -b < ...
- python、java实现二叉树,细说二叉树添加节点、深度优先(先序、中序、后续)遍历 、广度优先 遍历算法
数据结构可以说是编程的内功心法,掌握好数据结构真的非常重要.目前基本上流行的数据结构都是c和c++版本的,我最近在学习python,尝试着用python实现了二叉树的基本操作.写下一篇博文,总结一下, ...
- java配置环境变量,无法也行javac问题
最近换了公司,搭建开发环境的时候出了点小差错,写篇随笔记录下,下载jdk的时候要选择符合自己电脑的jdk版本,位数. 笔者之前下载的时候没注意下了个32bit的jdk,开发用eclipse的时候打不开 ...
- win10下安装Ubuntu16.04双系统
其实我是不喜欢系统的,之前都是在win下面进行开发,现在来了个项目,经过各种环境的安装调研,最终选择在Ubuntu下面进行开发.之前想着为啥不在虚拟机里面安装Ubuntu进行操作呢,由于虚拟机的体验不 ...