1. 安装redis
1. Windows安装
安装参考地址,点击此处。
启动redis: redis-server.exeredis.windows.conf
客户端连接验证redis: redis-cli.exe-h 127.0.0.1 -p 6379
客户端可视化工具: Redis Client / FastRedis
运行状态监控:CacheCloud
1. Linux安装
tar -zvxf redis-3.2.9.tar.gz
ln -s redis-3.2.9.tar.gz redis
cd redis
make
make install
允许其他客户端地址访问:
打开redis.conf文件注释掉bind 127.0.0.1
配置环境变量:vi /etc/profile
export REDIS_HOME=/usr/local/software/redis export PATH=$PATH:$REDIS_HOME/bin |
source /etc/profile 生效 |
启动:
redis-server /usr/local/software/redis/redis.conf |
停止:
redis-cli shutdown |
kill redis进程的pid 比如: kill -9 1420 |
配置redis密码:进入redis.conf
requirepass your_password |
保存重启 |
2. Docker安装redis
mkdir ~/redis cd redis docker pull redis:3.2 docker ps |
docker run -d -ti \ -p 7481:6379 \ -v /project/pos/conf/redis.conf:/etc/redis/redis.conf \ -v /project/pos/data:/data \ --restart always \ --name pos_redis \ daocloud.io/redis \ redis-server /etc/redis/redis.conf |
docker exec -it ${CONTAINER_ID} redis-cli
|
1. Redis作为mybatis二级缓存
1. 添加依赖
<!-- 持久化和缓存 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.1.0</version> <exclusions> <exclusion> <artifactId>tomcat-jdbc</artifactId> <groupId>org.apache.tomcat</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.5</version> <scope>test</scope> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> |
2. 参数配置
spring: redis: database: 0 host: 127.0.0.1 port: 6379 password: pool: max-active: 8 max-wait: -1 max-idle: 8 min-idle: 0 timeout: 0 #连接超时时长 data-timeout: 10 #数据缓存超时时长(秒) |
3. 缓存方式参数java配置
package com.svw.tbox.tcloud.commons.ms.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper;
/** * <p>ClassName: RedisConfig</p> * <p>Description: Redis缓存配置</p> * <p> Author: hurf</p> * <p> Date: 2017年11月16日</p> */ @Configuration @EnableCaching publicclass RedisConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") privateintport; @Value("${spring.redis.timeout}") privateinttimeout; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.data-timeout}") privateintdataTimeout;
/** * <p> Title: 生成key </p> * <p>Description: key组成:类名+方法名+参数值</p> * @return */ @Bean public KeyGenerator keyGenerator() { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } returnsb.toString(); }; }
/** * <p>Title: 配置连接参数</p> * <p>Description: 配置ip/主机名、端口、密码、连接超时时间</p> * @return */ @Bean public JedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(host); factory.setPort(port); factory.setPassword(password); factory.setTimeout(timeout); // 设置连接超时时间 returnfactory; }
/** * <p>Title: 设置数据缓存默认超时时长</p> * <p>Description: 以秒为单位</p> * @param redisTemplate * @return CacheManager */ @Bean public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); cacheManager.setDefaultExpiration(dataTimeout); returncacheManager; }
/** * <p>Title: 设置序列化工具,开启事务</p> * <p> Description: 这样ReportBean不需要实现Serializable</p> * @param factory * @return RedisTemplate */ @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { StringRedisTemplate template = new StringRedisTemplate(factory); template.setEnableTransactionSupport(true);//开启事务支持 ,在方法或者类上统一使用@Transactional标注事务 setSerializer(template); template.afterPropertiesSet(); returntemplate; }
@SuppressWarnings("unchecked") privatevoid setSerializer(StringRedisTemplate template) { @SuppressWarnings("rawtypes") Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); } } |
4. 非Mybatis 二级缓存,RedisTemplate封装
//接口 /** * RedisService.java * Created at 2017年11月18日 * Created by hurf * Copyright (C) 2017 XXX, All rights reserved. */ package com.svw.tbox.tcloud.gateway.service;
import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.stereotype.Service;
import com.svw.tbox.tcloud.commons.util.JSONUtil; import com.svw.tbox.tcloud.commons.util.LogUtil;
/** * <p>ClassName: RedisService</p> * <p>Description: RedisTemplate常用方法类</p> * <p>Author: hurf</p> * <p>Date: 2017年11月18日</p> */ @Service public class JedisTemplate {
public JedisTemplate() { super(); }
@Autowired private RedisTemplate<String, ?> redisTemplate;
/** * * <p>Title: 新增POJO对象</p> * <p>Description: </p> * @param key * @param value * @return */ public <T> boolean set(final String key, final T value) { return set(key, JSONUtil.toJson(value)); }
/** * * <p>Title: 新增POJO对象带过期时间</p> * <p>Description: 单位秒</p> * @param key * @param value * @param timeout 秒 * @return */ public <T> boolean set(String key, T value, long timeout) { return set(key, JSONUtil.toJson(value), timeout); }
/** * * <p>Title: 从缓存取出一个POJO类</p> * <p>Description: </p> * @param key * @param clz * @return */ public <T> T get(final String key, Class<T> clz) { return JSONUtil.toBean(get(key), clz); }
/** * * <p>Title: 新增字符串</p> * <p>Description: </p> * @param key * @param value * @return */ public boolean set(final String key, final String value) { boolean result = redisTemplate.execute(new RedisCallback<Boolean>() { public Boolean doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); connection.set(serializer.serialize(key), serializer.serialize(value)); return true; } });
return result; }
/** * * <p>Title: 新增字符串带过期时间</p> * <p>Description: 单位秒</p> * @param key * @param value * @param timeout * @return */ public boolean set(String key, String value, long timeout) { boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); connection.set(serializer.serialize(key), serializer.serialize(value)); return true; } });
redisTemplate.expire(key, timeout, TimeUnit.SECONDS); return result; }
/** * * <p>Title: 获取字符串</p> * <p>Description: </p> * @param key * @return */ public String get(final String key) { String result = redisTemplate.execute(new RedisCallback<String>() {
public String doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); byte[] value = connection.get(serializer.serialize(key)); return serializer.deserialize(value); } }); return result; }
/** * * <p>Title: 判断是否存在</p> * <p>Description: </p> * @param key * @return */ public boolean isExists(final String key) { return redisTemplate.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException { RedisSerializer<String> serializer = redisTemplate.getStringSerializer(); return connection.exists(serializer.serialize(key)); } }); }
/** * * <p>Title: 指定节点过期时间</p> * <p>Description: 单位 秒</p> * @param key * @param expire * @return */ public boolean expire(final String key, long expire) { return redisTemplate.expire(key, expire, TimeUnit.SECONDS); }
/** * * <p>Title: 删除一个节点</p> * <p>Description: </p> * @param key */ public void evict(String key) { redisTemplate.delete(key); }
/** * * <p>Title: 删除节点</p> * <p>Description: </p> * @param key * @return 是否删除成功 */ public boolean delete(String key) { try { evict(key); return true; } catch (Exception e) { LogUtil.error(()->e.getMessage()+"===>>>"+e.getCause()); return false; } }
/** * * <p>Title: 查询数据库节点数</p> * <p>Description: </p> * @return */ public Long dbSize() {
return redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException { return connection.dbSize(); } });
}
/** * * <p>Title: 清空数据</p> * <p>Description: </p> * @return */ public Boolean flushDB() { return redisTemplate.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException { connection.flushDb(); return true; } }); }
/** * * <p>Title: 存入列表</p> * <p>Description: </p> * @param key * @param list * @return */ public <T> boolean setList(String key, List<T> list) { String value = JSONUtil.toJson(list); return set(key, value); }
/** * * <p>Title: 获取列表</p> * <p>Description: </p> * @param key * @param clz * @return */ public <T> List<T> getList(String key, Class<T> clz) { List<T> list = new ArrayList<>(); String json = get(key); if (json != null) { list = JSONUtil.toList(json, clz); } return list; }
/** * * <p>Title: 清空所有缓存</p> * <p>Description: </p> * @return */ public Boolean flushAll() { return redisTemplate.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException { connection.flushAll(); return true; } }); }
} |
|
5. 效果一
1. 封装单表缓存(只缓存查询结果)
/** * GateBaseService.java * Created at 2017年11月19日 * Created by hurf * Copyright (C) 2017 XXX, All rights reserved. */ package com.svw.tbox.tcloud.gateway.service;
import java.util.List;
import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; import org.springframework.transaction.annotation.Transactional;
import com.svw.tbox.tcloud.common.biz.BaseService;
import tk.mybatis.mapper.common.Mapper;
/** * <p>ClassName: GateBaseService</p> * <p>Description: 缓存到Redis的单表CURD类,缓存名gateway,key规则是类名+方法名+参数值</p> * <p>Author: hurf</p> * <p>Date: 2017年11月19日</p> */ @Transactional @CacheConfig(cacheNames = "gateway",keyGenerator="keyGenerator") public class BaseService4Gateway<M extends Mapper<T>, T extends Object> extends BaseService<M, T>{
/** * <p>Title: 查询一条数据</p> * <p>Description: </p> * @param entity * @return */ @Cacheable public T selectOneAndCache(T entity) { return mapper.selectOne(entity); }
/** * 主键字段查询 * @param id * @return */ @Cacheable public T selectByIdAndCache(Object id) { return mapper.selectByPrimaryKey(id); }
/** * <p>Title: 根据字段查询单表数据</p> * <p>Description: </p> * @param entity * @return */ @Cacheable public List<T> selectListAndCache(T entity) { return mapper.select(entity); }
/** * 查询单表所有数据 * @return */ @Cacheable public List<T> selectListAllAndCache() { return mapper.selectAll(); }
/** * 查询所有对象数量 * @return */ @Cacheable public int selectCountAllAndCache() { return mapper.selectCount(null); }
/** * 指定几个字段,查询数量 * @param entity * @return */ @Cacheable public int selectCountAndCache(T entity) { return mapper.selectCount(entity); }
/** * <p>Title: 动态条件查询单表</p> * <p>Description: </p> * @param example * @return * <p>使用举例(Service类方法中使用): * UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("joe"); criteria.andUsernameIsNull(); example.setOrderByClause("username asc,email desc"); List<?> list = selectByExample(example); 相当于: select * from user where username = 'joe' and username is null order by username asc,email desc * </p> */ @Cacheable public List<T> selectByExampleAndCache(Object example) { return mapper.selectByExample(example); }
/** * * <p>Title: 动态条件查询单表数目</p> * <p>Description: </p> * @param example * @return * */ @Cacheable public int selectCountByExampleAndCache(Object example) { return mapper.selectCountByExample(example); } } |
2. 应用
import org.springframework.stereotype.Service; import com.svw.tbox.tcloud.gateway.dao.GUserTokenMapper; import com.svw.tbox.tcloud.gateway.entity.GUserToken;
/** * <p>ClassName: GUserTokenService</p> * <p>Description: Token服务</p> * <p>Author: hurf</p> * <p>Date: 2017年11月19日</p> */ @Service publicclass GUserTokenService extends BaseService4Gateway<GUserTokenMapper, GUserToken>{ } |
//控制器 @RestController @RequestMapping("/auth") @Api( publicclass AuthController {
@Autowired private GUserTokenService gUserTokenService;
@ApiOperation(value = "新增票剧") @ApiImplicitParams({ @ApiImplicitParam(name = "refreshToken", value = "身份票剧", paramType = "query", required = true), @ApiImplicitParam(name = "refreshTokenDeadline", value = "身份票剧过期时间", paramType = "query", required = true), @ApiImplicitParam(name = "accessToken", value = "访问票据", paramType = "query", required = true), @ApiImplicitParam(name = "accessTokenDeadline", value = "访问票剧过期时间", paramType = "query", required = true) }) @RequestMapping(value = "/tokenAdd", method = RequestMethod.POST) public Result tokenAdd(GUserToken entity) { return Result.success(gUserTokenService.insertSelective(entity)); } |
3. 访问查询
http://localhost:8200/swagger-ui.html
第一次执行all查询(查询的是数据库):
第二次执行all查询:没有出现查询语句查询缓存
已经存在
1. 使用方式二
@Service @CacheConfig(cacheNames = "ordertraceid-resource") public class CacheServiceImpl implements CacheService {
@Autowired private IdGenerator idGenerator;
@Override @Cacheable(key = "#accountId+'-'+#orderId+'-'+#eventCode+'-ordertraceid-resource'") public String getOrderTraceId(String accountId,String orderId, int eventCode){ return String.valueOf(idGenerator.generate()); } @Override @CacheEvict(key = "#accountId+'-'+#orderId+'-'+#eventCode+'-ordertraceid-resource'") public void removeOrderTraceId(String accountId,String orderId, int eventCode){ } } |